@useago/sdk 1.4.4 → 1.5.2

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.
Files changed (50) hide show
  1. package/CHANGELOG.md +63 -1
  2. package/dist/AgoClient-5VGybmvz.cjs +8 -0
  3. package/dist/AgoClient-DXrH2AMi.js +964 -0
  4. package/dist/angular.cjs +1 -1
  5. package/dist/angular.d.cts +124 -5
  6. package/dist/angular.d.ts +124 -5
  7. package/dist/angular.js +5 -1
  8. package/dist/autoContinue-CC8K9mBU.js +63 -0
  9. package/dist/autoContinue-CP9pJR-V.cjs +1 -0
  10. package/dist/{createConversationSession-CUkNp6mZ.cjs → createConversationSession-0WTqcCLK.cjs} +1 -1
  11. package/dist/{createConversationSession-QIBN0gLx.js → createConversationSession-DPrrr70o.js} +1 -1
  12. package/dist/createFormCollector-1GKKwQV_.cjs +1 -0
  13. package/dist/{createFormCollector-F3YJfsbg.js → createFormCollector-DYh90kiG.js} +97 -91
  14. package/dist/devtools.d.cts +82 -5
  15. package/dist/devtools.d.ts +82 -5
  16. package/dist/functions-CPs7omgM.cjs +1 -0
  17. package/dist/helpers.cjs +1 -1
  18. package/dist/helpers.d.cts +5 -0
  19. package/dist/helpers.d.ts +5 -0
  20. package/dist/helpers.js +1 -1
  21. package/dist/index.cjs +1 -1
  22. package/dist/index.d.cts +147 -7
  23. package/dist/index.d.ts +147 -7
  24. package/dist/index.js +45 -43
  25. package/dist/react.cjs +3 -3
  26. package/dist/react.d.cts +191 -21
  27. package/dist/react.d.ts +191 -21
  28. package/dist/react.js +666 -529
  29. package/dist/testing.cjs +1 -1
  30. package/dist/testing.d.cts +82 -5
  31. package/dist/testing.d.ts +82 -5
  32. package/dist/testing.js +1 -1
  33. package/dist/vue.cjs +1 -1
  34. package/dist/vue.d.cts +82 -5
  35. package/dist/vue.d.ts +82 -5
  36. package/dist/vue.js +1 -1
  37. package/dist/widget.cjs +4 -4
  38. package/dist/widget.d.cts +82 -5
  39. package/dist/widget.d.ts +82 -5
  40. package/dist/widget.js +437 -423
  41. package/llms-full.txt +100 -6
  42. package/package.json +1 -1
  43. package/dist/AgoClient-CLmtYTJx.cjs +0 -8
  44. package/dist/AgoClient-Ozz2b1dQ.js +0 -912
  45. package/dist/createFormCollector-DHT1ObOb.cjs +0 -1
  46. package/dist/functions-Djnq-JAo.cjs +0 -1
  47. package/dist/rolldown-runtime-16Nf8qvH.cjs +0 -1
  48. /package/dist/{createMockClient-BSr-UV8R.cjs → createMockClient-C-wrjb2C.cjs} +0 -0
  49. /package/dist/{createMockClient-bAZ9KBHC.js → createMockClient-we-XoPom.js} +0 -0
  50. /package/dist/{functions-CApuQZ2b.js → functions-tzyOZNp6.js} +0 -0
package/dist/angular.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./AgoClient-CLmtYTJx.cjs");var n=class{constructor(e){this.client=new o.AgoClient(e),this.messages$=this.fromEvent("message:complete"),this.chunks$=this.fromEvent("message:chunk"),this.errors$=this.fromEvent("message:error"),this.messageStart$=this.fromEvent("message:start")}fromEvent(e){const t=this.client;return{subscribe(i){const s=r=>{i.next?.(r)};return t.on(e,s),{unsubscribe:()=>t.off(e,s)}}}}sendMessage(e,t){return this.client.sendMessage(e,t)}getConversations(){return this.client.getConversations()}getConversation(e){return this.client.getConversation(e)}getMessages(e){return this.client.getMessages(e)}submitToolCallForm(e,t){return this.client.submitToolCallForm(e,t)}confirmToolCall(e){return this.client.confirmToolCall(e)}rejectToolCall(e){return this.client.rejectToolCall(e)}submitFeedback(e,t){return this.client.submitFeedback(e,t)}registerFunction(e,t,i){typeof e=="object"?this.client.registerFunction(e):this.client.registerFunction(e,t,i)}unregisterFunction(e){return this.client.unregisterFunction(e)}registerNavigationFunction(e,t){this.client.registerNavigationFunction(e,t)}unregisterNavigationFunction(){this.client.unregisterNavigationFunction()}registerPageStateFunction(e,t){this.client.registerPageStateFunction(e,t)}unregisterPageStateFunction(e){this.client.unregisterPageStateFunction(e)}on(e,t){this.client.on(e,t)}off(e,t){this.client.off(e,t)}updateConfig(e){this.client.updateConfig(e)}getClient(){return this.client}destroy(){this.client.destroy()}};function c(e){return{provide:n,useValue:new n(e)}}exports.AgoService=n;exports.provideAgo=c;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./AgoClient-5VGybmvz.cjs"),c=require("./autoContinue-CP9pJR-V.cjs");var n=class{constructor(t){this.client=new o.AgoClient(t),this.messages$=this.fromEvent("message:complete"),this.chunks$=this.fromEvent("message:chunk"),this.errors$=this.fromEvent("message:error"),this.messageStart$=this.fromEvent("message:start")}fromEvent(t){const e=this.client;return{subscribe(i){const r=s=>{i.next?.(s)};return e.on(t,r),{unsubscribe:()=>e.off(t,r)}}}}sendMessage(t,e){return this.client.sendMessage(t,e)}getConversations(){return this.client.getConversations()}getConversation(t){return this.client.getConversation(t)}getMessages(t){return this.client.getMessages(t)}submitToolCallForm(t,e){return this.client.submitToolCallForm(t,e)}confirmToolCall(t){return this.client.confirmToolCall(t)}rejectToolCall(t){return this.client.rejectToolCall(t)}submitFeedback(t,e){return this.client.submitFeedback(t,e)}registerFunction(t,e,i){typeof t=="object"?this.client.registerFunction(t):this.client.registerFunction(t,e,i)}unregisterFunction(t){return this.client.unregisterFunction(t)}registerNavigationFunction(t,e){this.client.registerNavigationFunction(t,e)}unregisterNavigationFunction(){this.client.unregisterNavigationFunction()}enableAutoContinueAfterNavigation(t){return c.attachAutoContinueAfterNavigation(this.client,t)}registerPageStateFunction(t,e){this.client.registerPageStateFunction(t,e)}unregisterPageStateFunction(t){this.client.unregisterPageStateFunction(t)}on(t,e){this.client.on(t,e)}off(t,e){this.client.off(t,e)}updateConfig(t){this.client.updateConfig(t)}getClient(){return this.client}destroy(){this.client.destroy()}};function u(t){return{provide:n,useValue:new n(t)}}exports.AgoService=n;exports.provideAgo=u;
@@ -28,6 +28,23 @@ declare interface AgoAttachment {
28
28
  isSafeImage: boolean;
29
29
  }
30
30
 
31
+ export declare interface AgoAutoContinueOptions {
32
+ /** Function names whose invocation counts as "navigated". Default `["navigateToPage"]`. */
33
+ navigationFunctions?: string[];
34
+ /** Registered function that signals the destination has editable state. Default `"setPageState"`. */
35
+ pageStateFunctionName?: string;
36
+ /** The hidden continuation prompt. Override for i18n / tone. */
37
+ continuationPrompt?: string;
38
+ /** Max continuations per user gesture (guards navigate→continue→navigate loops). Default `1`. */
39
+ maxDepth?: number;
40
+ /** How long to wait for the destination page to register page-state before giving up. Default `4000`ms. */
41
+ readinessTimeoutMs?: number;
42
+ /** Extra settle delay after page-state appears, to let sibling state mount. Default `150`ms. */
43
+ settleMs?: number;
44
+ /** Opt-out escape hatch. Default `true`. */
45
+ enabled?: boolean;
46
+ }
47
+
31
48
  /**
32
49
  * Main SDK client for AGO Chat integration
33
50
  */
@@ -41,6 +58,12 @@ declare class AgoClient {
41
58
  private warnedEmptyConversations;
42
59
  /** Paused turns awaiting auto-resume, keyed by assistant message id. */
43
60
  private pendingResumes;
61
+ /**
62
+ * Client function invocations held pending user approval, keyed by
63
+ * invocationId (the tool-call id). Populated when {@link requiresApproval}
64
+ * matches; drained by {@link approveFunction} / {@link rejectFunction}.
65
+ */
66
+ private pendingApprovals;
44
67
  /** App-provided gate deciding WHEN a paused turn resumes (see {@link registerResumeGate}). */
45
68
  private resumeGate;
46
69
  constructor(config: AgoConfig);
@@ -91,6 +114,24 @@ declare class AgoClient {
91
114
  */
92
115
  private maybeFlagEmptyReply;
93
116
  private handleClientFunctionInvocation;
117
+ /**
118
+ * Whether a client function invocation must wait for explicit user approval.
119
+ * True when the {@link AgoConfig.approvalPolicy} returns true OR the function
120
+ * was registered with `requiresApproval: true` — the two OR together.
121
+ */
122
+ private requiresApproval;
123
+ /**
124
+ * Approve a client function call held by the approval gate: run it, submit its
125
+ * result, and let the paused turn resume. No-op if the invocation is unknown
126
+ * (already handled, or never gated).
127
+ */
128
+ approveFunction(invocationId: string): Promise<void>;
129
+ /**
130
+ * Reject a client function call held by the approval gate: submit a rejection
131
+ * result so the agent sees the user declined, and let the paused turn resume
132
+ * (the agent decides what to do next). No-op if the invocation is unknown.
133
+ */
134
+ rejectFunction(invocationId: string): Promise<void>;
94
135
  /**
95
136
  * Get list of conversations
96
137
  */
@@ -120,8 +161,10 @@ declare class AgoClient {
120
161
  *
121
162
  * Opt-in on purpose — re-running functions on reload can be surprising (e.g. a
122
163
  * navigation function would navigate again), so the app decides. Returns the
123
- * resumed turn's final message, or `null` when there was nothing to resume or
124
- * some waiting function is not registered on this page.
164
+ * resumed turn's final message, or `null` when there was nothing to resume,
165
+ * some waiting function is not registered on this page, or a waiting call is
166
+ * gated by the approval policy (it is held for `approveFunction` /
167
+ * `rejectFunction` and the turn stays paused, exactly as on the live stream).
125
168
  */
126
169
  resumePendingClientFunctions(conversation: Conversation): Promise<AgoMessage | null>;
127
170
  /**
@@ -416,6 +459,15 @@ export declare interface AgoClientEvents {
416
459
  "toolCall:received": ToolCallData;
417
460
  "toolCall:form": ToolCallData;
418
461
  "function:invoke": ClientFunctionInvocation;
462
+ /**
463
+ * A client function call is held pending the user's approval (pause mode +
464
+ * an {@link AgoConfig.approvalPolicy}/`requiresApproval` match). The turn stays
465
+ * at `WAITING_CLIENT`; call `approveFunction(invocationId)` to run it and
466
+ * resume, or `rejectFunction(invocationId)` to decline. Fires after
467
+ * `function:invoke` (which still fires for every call) and instead of the
468
+ * call running immediately.
469
+ */
470
+ "function:awaiting-approval": ClientFunctionInvocation;
419
471
  "function:result": {
420
472
  invocationId: string;
421
473
  result: unknown;
@@ -476,14 +528,28 @@ export declare interface AgoConfig {
476
528
  warnOnEmptyReply?: boolean;
477
529
  /**
478
530
  * How the agent loop treats client function calls (requires backend support):
479
- * - `"placeholder"` (default): the turn continues immediately on a placeholder
480
- * result; the real result is only visible to the agent on later turns.
481
- * - `"pause"`: the turn stops on client function call(s) with status
531
+ * - `"pause"` (default): the turn stops on client function call(s) with status
482
532
  * `WAITING_CLIENT`; once every result is submitted, the SDK resumes the SAME
483
533
  * turn via `POST /messages/{id}/continue`, so the agent sees the real results.
534
+ * - `"placeholder"` (legacy): the turn continues immediately on a placeholder
535
+ * result; the real result is only visible to the agent on later turns.
484
536
  * Older backends ignore the flag, so `"pause"` degrades to legacy behavior.
485
537
  */
486
538
  clientFunctionsMode?: ClientFunctionsMode;
539
+ /**
540
+ * Gate client function calls behind explicit user approval. Return `true` for
541
+ * an invocation the user must approve/reject before it runs; return `false`
542
+ * (or omit the policy) to let it run immediately as before.
543
+ *
544
+ * Only effective in pause mode (`clientFunctionsMode: "pause"`) — a gated call
545
+ * holds at `WAITING_CLIENT`, the SDK emits `function:awaiting-approval`, and it
546
+ * runs (and the turn resumes) only after `approveFunction(invocationId)`; a
547
+ * `rejectFunction(invocationId)` submits a rejection so the agent sees the
548
+ * decline. In placeholder mode there is no pause to hold, so the policy is a
549
+ * no-op and the call runs normally. A per-function `requiresApproval: true`
550
+ * also gates a call; the policy and the flag OR together.
551
+ */
552
+ approvalPolicy?: (invocation: ClientFunctionInvocation) => boolean;
487
553
  /**
488
554
  * Max serialized size (bytes) of a client function result before the SDK
489
555
  * replaces it with a flagged, truncated preview. Everything a handler
@@ -528,6 +594,11 @@ export declare interface AgoMessage {
528
594
  export declare interface AgoPageStateOptions {
529
595
  /** Name of the synthesized client function. Defaults to "setPageState". */
530
596
  functionName?: string;
597
+ /**
598
+ * Require explicit user approval before this state change runs. See
599
+ * {@link AgoConfig.approvalPolicy} — pause mode only. Defaults to `false`.
600
+ */
601
+ requiresApproval?: boolean;
531
602
  }
532
603
 
533
604
  export declare type AgoProvideOptions = AgoConfig;
@@ -609,6 +680,31 @@ export declare class AgoService {
609
680
  }>): void;
610
681
  /** Unregister navigation (function + current-page context) */
611
682
  unregisterNavigationFunction(): void;
683
+ /**
684
+ * Auto-continue the agent after it navigates, so a "go to page B and change X"
685
+ * request completes in one user gesture. Enable once (e.g. in your root
686
+ * component) and call the returned function on teardown:
687
+ *
688
+ * ```ts
689
+ * export class AppComponent implements OnDestroy {
690
+ * private ago = inject(AgoService);
691
+ * private router = inject(Router);
692
+ * private stopAutoContinue = this.ago.enableAutoContinueAfterNavigation();
693
+ *
694
+ * constructor() {
695
+ * this.ago.registerNavigationFunction((path) => this.router.navigateByUrl(path), routes);
696
+ * }
697
+ *
698
+ * ngOnDestroy() {
699
+ * this.stopAutoContinue();
700
+ * }
701
+ * }
702
+ * ```
703
+ *
704
+ * See {@link attachAutoContinueAfterNavigation} for the pause-mode /
705
+ * placeholder-mode mechanics and the available options.
706
+ */
707
+ enableAutoContinueAfterNavigation(options?: AgoAutoContinueOptions): () => void;
612
708
  /** Register editable page-state controls (filters, sort, view mode…) */
613
709
  registerPageStateFunction(controls: AgoStateControl[], opts?: AgoPageStateOptions): void;
614
710
  /** Unregister a page-state function and its dynamic context */
@@ -684,6 +780,11 @@ declare interface ClientFunctionDefinition {
684
780
  * `Infinity` disables the guard for this function.
685
781
  */
686
782
  maxResultBytes?: number;
783
+ /**
784
+ * Require explicit user approval before this function runs. See
785
+ * {@link AgoConfig.approvalPolicy} — pause mode only. ORs with the policy.
786
+ */
787
+ requiresApproval?: boolean;
687
788
  }
688
789
 
689
790
  /**
@@ -710,6 +811,11 @@ declare type ClientFunctionRegisterOptions = Omit<ClientFunctionSchema, "name">
710
811
  * disables the guard for this function.
711
812
  */
712
813
  maxResultBytes?: number;
814
+ /**
815
+ * Require explicit user approval before this function runs. See
816
+ * {@link AgoConfig.approvalPolicy} — pause mode only. ORs with the policy.
817
+ */
818
+ requiresApproval?: boolean;
713
819
  };
714
820
 
715
821
  /**
@@ -750,6 +856,19 @@ declare interface ContextEntry {
750
856
  description?: string;
751
857
  /** Arbitrary structured data the AI should know about */
752
858
  data?: Record<string, unknown>;
859
+ /**
860
+ * Marks the entry as constant for the whole conversation. The backend then
861
+ * pins it right after the system prompt, where LLM providers cache it across
862
+ * turns, instead of re-processing it next to every new user message.
863
+ *
864
+ * Only set this when the entry's content is byte-identical on every message
865
+ * of a conversation (a schema, a capability list, static instructions). A
866
+ * stable entry that changes between messages invalidates the provider's
867
+ * cache for the entire conversation history, which costs more than leaving
868
+ * the flag off. Default: `false` (re-sent near the newest user message).
869
+ * Backends that don't know the flag ignore it.
870
+ */
871
+ stable?: boolean;
753
872
  }
754
873
 
755
874
  /**
package/dist/angular.d.ts CHANGED
@@ -28,6 +28,23 @@ declare interface AgoAttachment {
28
28
  isSafeImage: boolean;
29
29
  }
30
30
 
31
+ export declare interface AgoAutoContinueOptions {
32
+ /** Function names whose invocation counts as "navigated". Default `["navigateToPage"]`. */
33
+ navigationFunctions?: string[];
34
+ /** Registered function that signals the destination has editable state. Default `"setPageState"`. */
35
+ pageStateFunctionName?: string;
36
+ /** The hidden continuation prompt. Override for i18n / tone. */
37
+ continuationPrompt?: string;
38
+ /** Max continuations per user gesture (guards navigate→continue→navigate loops). Default `1`. */
39
+ maxDepth?: number;
40
+ /** How long to wait for the destination page to register page-state before giving up. Default `4000`ms. */
41
+ readinessTimeoutMs?: number;
42
+ /** Extra settle delay after page-state appears, to let sibling state mount. Default `150`ms. */
43
+ settleMs?: number;
44
+ /** Opt-out escape hatch. Default `true`. */
45
+ enabled?: boolean;
46
+ }
47
+
31
48
  /**
32
49
  * Main SDK client for AGO Chat integration
33
50
  */
@@ -41,6 +58,12 @@ declare class AgoClient {
41
58
  private warnedEmptyConversations;
42
59
  /** Paused turns awaiting auto-resume, keyed by assistant message id. */
43
60
  private pendingResumes;
61
+ /**
62
+ * Client function invocations held pending user approval, keyed by
63
+ * invocationId (the tool-call id). Populated when {@link requiresApproval}
64
+ * matches; drained by {@link approveFunction} / {@link rejectFunction}.
65
+ */
66
+ private pendingApprovals;
44
67
  /** App-provided gate deciding WHEN a paused turn resumes (see {@link registerResumeGate}). */
45
68
  private resumeGate;
46
69
  constructor(config: AgoConfig);
@@ -91,6 +114,24 @@ declare class AgoClient {
91
114
  */
92
115
  private maybeFlagEmptyReply;
93
116
  private handleClientFunctionInvocation;
117
+ /**
118
+ * Whether a client function invocation must wait for explicit user approval.
119
+ * True when the {@link AgoConfig.approvalPolicy} returns true OR the function
120
+ * was registered with `requiresApproval: true` — the two OR together.
121
+ */
122
+ private requiresApproval;
123
+ /**
124
+ * Approve a client function call held by the approval gate: run it, submit its
125
+ * result, and let the paused turn resume. No-op if the invocation is unknown
126
+ * (already handled, or never gated).
127
+ */
128
+ approveFunction(invocationId: string): Promise<void>;
129
+ /**
130
+ * Reject a client function call held by the approval gate: submit a rejection
131
+ * result so the agent sees the user declined, and let the paused turn resume
132
+ * (the agent decides what to do next). No-op if the invocation is unknown.
133
+ */
134
+ rejectFunction(invocationId: string): Promise<void>;
94
135
  /**
95
136
  * Get list of conversations
96
137
  */
@@ -120,8 +161,10 @@ declare class AgoClient {
120
161
  *
121
162
  * Opt-in on purpose — re-running functions on reload can be surprising (e.g. a
122
163
  * navigation function would navigate again), so the app decides. Returns the
123
- * resumed turn's final message, or `null` when there was nothing to resume or
124
- * some waiting function is not registered on this page.
164
+ * resumed turn's final message, or `null` when there was nothing to resume,
165
+ * some waiting function is not registered on this page, or a waiting call is
166
+ * gated by the approval policy (it is held for `approveFunction` /
167
+ * `rejectFunction` and the turn stays paused, exactly as on the live stream).
125
168
  */
126
169
  resumePendingClientFunctions(conversation: Conversation): Promise<AgoMessage | null>;
127
170
  /**
@@ -416,6 +459,15 @@ export declare interface AgoClientEvents {
416
459
  "toolCall:received": ToolCallData;
417
460
  "toolCall:form": ToolCallData;
418
461
  "function:invoke": ClientFunctionInvocation;
462
+ /**
463
+ * A client function call is held pending the user's approval (pause mode +
464
+ * an {@link AgoConfig.approvalPolicy}/`requiresApproval` match). The turn stays
465
+ * at `WAITING_CLIENT`; call `approveFunction(invocationId)` to run it and
466
+ * resume, or `rejectFunction(invocationId)` to decline. Fires after
467
+ * `function:invoke` (which still fires for every call) and instead of the
468
+ * call running immediately.
469
+ */
470
+ "function:awaiting-approval": ClientFunctionInvocation;
419
471
  "function:result": {
420
472
  invocationId: string;
421
473
  result: unknown;
@@ -476,14 +528,28 @@ export declare interface AgoConfig {
476
528
  warnOnEmptyReply?: boolean;
477
529
  /**
478
530
  * How the agent loop treats client function calls (requires backend support):
479
- * - `"placeholder"` (default): the turn continues immediately on a placeholder
480
- * result; the real result is only visible to the agent on later turns.
481
- * - `"pause"`: the turn stops on client function call(s) with status
531
+ * - `"pause"` (default): the turn stops on client function call(s) with status
482
532
  * `WAITING_CLIENT`; once every result is submitted, the SDK resumes the SAME
483
533
  * turn via `POST /messages/{id}/continue`, so the agent sees the real results.
534
+ * - `"placeholder"` (legacy): the turn continues immediately on a placeholder
535
+ * result; the real result is only visible to the agent on later turns.
484
536
  * Older backends ignore the flag, so `"pause"` degrades to legacy behavior.
485
537
  */
486
538
  clientFunctionsMode?: ClientFunctionsMode;
539
+ /**
540
+ * Gate client function calls behind explicit user approval. Return `true` for
541
+ * an invocation the user must approve/reject before it runs; return `false`
542
+ * (or omit the policy) to let it run immediately as before.
543
+ *
544
+ * Only effective in pause mode (`clientFunctionsMode: "pause"`) — a gated call
545
+ * holds at `WAITING_CLIENT`, the SDK emits `function:awaiting-approval`, and it
546
+ * runs (and the turn resumes) only after `approveFunction(invocationId)`; a
547
+ * `rejectFunction(invocationId)` submits a rejection so the agent sees the
548
+ * decline. In placeholder mode there is no pause to hold, so the policy is a
549
+ * no-op and the call runs normally. A per-function `requiresApproval: true`
550
+ * also gates a call; the policy and the flag OR together.
551
+ */
552
+ approvalPolicy?: (invocation: ClientFunctionInvocation) => boolean;
487
553
  /**
488
554
  * Max serialized size (bytes) of a client function result before the SDK
489
555
  * replaces it with a flagged, truncated preview. Everything a handler
@@ -528,6 +594,11 @@ export declare interface AgoMessage {
528
594
  export declare interface AgoPageStateOptions {
529
595
  /** Name of the synthesized client function. Defaults to "setPageState". */
530
596
  functionName?: string;
597
+ /**
598
+ * Require explicit user approval before this state change runs. See
599
+ * {@link AgoConfig.approvalPolicy} — pause mode only. Defaults to `false`.
600
+ */
601
+ requiresApproval?: boolean;
531
602
  }
532
603
 
533
604
  export declare type AgoProvideOptions = AgoConfig;
@@ -609,6 +680,31 @@ export declare class AgoService {
609
680
  }>): void;
610
681
  /** Unregister navigation (function + current-page context) */
611
682
  unregisterNavigationFunction(): void;
683
+ /**
684
+ * Auto-continue the agent after it navigates, so a "go to page B and change X"
685
+ * request completes in one user gesture. Enable once (e.g. in your root
686
+ * component) and call the returned function on teardown:
687
+ *
688
+ * ```ts
689
+ * export class AppComponent implements OnDestroy {
690
+ * private ago = inject(AgoService);
691
+ * private router = inject(Router);
692
+ * private stopAutoContinue = this.ago.enableAutoContinueAfterNavigation();
693
+ *
694
+ * constructor() {
695
+ * this.ago.registerNavigationFunction((path) => this.router.navigateByUrl(path), routes);
696
+ * }
697
+ *
698
+ * ngOnDestroy() {
699
+ * this.stopAutoContinue();
700
+ * }
701
+ * }
702
+ * ```
703
+ *
704
+ * See {@link attachAutoContinueAfterNavigation} for the pause-mode /
705
+ * placeholder-mode mechanics and the available options.
706
+ */
707
+ enableAutoContinueAfterNavigation(options?: AgoAutoContinueOptions): () => void;
612
708
  /** Register editable page-state controls (filters, sort, view mode…) */
613
709
  registerPageStateFunction(controls: AgoStateControl[], opts?: AgoPageStateOptions): void;
614
710
  /** Unregister a page-state function and its dynamic context */
@@ -684,6 +780,11 @@ declare interface ClientFunctionDefinition {
684
780
  * `Infinity` disables the guard for this function.
685
781
  */
686
782
  maxResultBytes?: number;
783
+ /**
784
+ * Require explicit user approval before this function runs. See
785
+ * {@link AgoConfig.approvalPolicy} — pause mode only. ORs with the policy.
786
+ */
787
+ requiresApproval?: boolean;
687
788
  }
688
789
 
689
790
  /**
@@ -710,6 +811,11 @@ declare type ClientFunctionRegisterOptions = Omit<ClientFunctionSchema, "name">
710
811
  * disables the guard for this function.
711
812
  */
712
813
  maxResultBytes?: number;
814
+ /**
815
+ * Require explicit user approval before this function runs. See
816
+ * {@link AgoConfig.approvalPolicy} — pause mode only. ORs with the policy.
817
+ */
818
+ requiresApproval?: boolean;
713
819
  };
714
820
 
715
821
  /**
@@ -750,6 +856,19 @@ declare interface ContextEntry {
750
856
  description?: string;
751
857
  /** Arbitrary structured data the AI should know about */
752
858
  data?: Record<string, unknown>;
859
+ /**
860
+ * Marks the entry as constant for the whole conversation. The backend then
861
+ * pins it right after the system prompt, where LLM providers cache it across
862
+ * turns, instead of re-processing it next to every new user message.
863
+ *
864
+ * Only set this when the entry's content is byte-identical on every message
865
+ * of a conversation (a schema, a capability list, static instructions). A
866
+ * stable entry that changes between messages invalidates the provider's
867
+ * cache for the entire conversation history, which costs more than leaving
868
+ * the flag off. Default: `false` (re-sent near the newest user message).
869
+ * Backends that don't know the flag ignore it.
870
+ */
871
+ stable?: boolean;
753
872
  }
754
873
 
755
874
  /**
package/dist/angular.js CHANGED
@@ -1,4 +1,5 @@
1
- import { t as o } from "./AgoClient-Ozz2b1dQ.js";
1
+ import { t as o } from "./AgoClient-DXrH2AMi.js";
2
+ import { t as c } from "./autoContinue-CC8K9mBU.js";
2
3
  var s = class {
3
4
  constructor(t) {
4
5
  this.client = new o(t), this.messages$ = this.fromEvent("message:complete"), this.chunks$ = this.fromEvent("message:chunk"), this.errors$ = this.fromEvent("message:error"), this.messageStart$ = this.fromEvent("message:start");
@@ -48,6 +49,9 @@ var s = class {
48
49
  unregisterNavigationFunction() {
49
50
  this.client.unregisterNavigationFunction();
50
51
  }
52
+ enableAutoContinueAfterNavigation(t) {
53
+ return c(this.client, t);
54
+ }
51
55
  registerPageStateFunction(t, e) {
52
56
  this.client.registerPageStateFunction(t, e);
53
57
  }
@@ -0,0 +1,63 @@
1
+ var N = "You have navigated the user to a new page. That page now exposes its editable state through the available setPageState function, and its current values in the page context. If the user's latest request also asked to change something on this page, call setPageState now to apply exactly those changes and nothing else. Otherwise, reply with a short confirmation only.";
2
+ function p(e) {
3
+ return {
4
+ navigationFunctions: e?.navigationFunctions ?? ["navigateToPage"],
5
+ pageStateFunctionName: e?.pageStateFunctionName ?? "setPageState",
6
+ continuationPrompt: e?.continuationPrompt ?? N,
7
+ maxDepth: e?.maxDepth ?? 1,
8
+ readinessTimeoutMs: e?.readinessTimeoutMs ?? 4e3,
9
+ settleMs: e?.settleMs ?? 150,
10
+ enabled: e?.enabled ?? !0
11
+ };
12
+ }
13
+ function w(e, o) {
14
+ const a = typeof o == "function" ? () => p(o()) : () => p(o), t = {
15
+ navigated: !1,
16
+ pausedTurnNavigated: !1,
17
+ depth: 0,
18
+ runId: 0,
19
+ ourSendPending: !1
20
+ }, i = () => e.getRegisteredFunctions().some((n) => n.name === a().pageStateFunctionName), g = (n) => new Promise((s) => {
21
+ let l = !1;
22
+ const r = (I) => {
23
+ l || (l = !0, clearTimeout(S), e.off("context:changed", u), s(I));
24
+ }, v = () => setTimeout(() => r(n === t.runId && i()), a().settleMs), u = () => {
25
+ if (n !== t.runId) return r(!1);
26
+ i() && (e.off("context:changed", u), v());
27
+ }, S = setTimeout(() => r(!1), a().readinessTimeoutMs);
28
+ i() ? v() : e.on("context:changed", u);
29
+ }), P = async (n) => {
30
+ const s = ++t.runId;
31
+ if (!(!await g(s) || s !== t.runId)) {
32
+ t.depth += 1, t.ourSendPending = !0;
33
+ try {
34
+ await e.sendMessage(a().continuationPrompt, {
35
+ conversationId: n,
36
+ hidden: !0
37
+ });
38
+ } catch {
39
+ t.ourSendPending = !1;
40
+ }
41
+ }
42
+ }, d = (n) => {
43
+ a().navigationFunctions.includes(n.functionName) && (t.navigated = !0);
44
+ }, T = e.registerResumeGate(async () => {
45
+ a().enabled && t.pausedTurnNavigated && (t.pausedTurnNavigated = !1, await g(++t.runId));
46
+ }), f = () => {
47
+ t.pausedTurnNavigated = t.navigated, t.navigated = !1;
48
+ }, c = () => {
49
+ t.ourSendPending || (t.depth = 0, t.runId += 1);
50
+ }, h = (n) => {
51
+ t.ourSendPending = !1;
52
+ const s = t.navigated;
53
+ t.navigated = !1, a().enabled && s && (t.depth >= a().maxDepth || P(n.conversationId));
54
+ }, m = () => {
55
+ t.ourSendPending = !1;
56
+ };
57
+ return e.on("function:invoke", d), e.on("message:start", c), e.on("message:waiting-client", f), e.on("message:complete", h), e.on("message:error", m), () => {
58
+ t.runId += 1, T(), e.off("function:invoke", d), e.off("message:start", c), e.off("message:waiting-client", f), e.off("message:complete", h), e.off("message:error", m);
59
+ };
60
+ }
61
+ export {
62
+ w as t
63
+ };
@@ -0,0 +1 @@
1
+ var I="You have navigated the user to a new page. That page now exposes its editable state through the available setPageState function, and its current values in the page context. If the user's latest request also asked to change something on this page, call setPageState now to apply exactly those changes and nothing else. Otherwise, reply with a short confirmation only.";function p(e){return{navigationFunctions:e?.navigationFunctions??["navigateToPage"],pageStateFunctionName:e?.pageStateFunctionName??"setPageState",continuationPrompt:e?.continuationPrompt??I,maxDepth:e?.maxDepth??1,readinessTimeoutMs:e?.readinessTimeoutMs??4e3,settleMs:e?.settleMs??150,enabled:e?.enabled??!0}}function w(e,s){const a=typeof s=="function"?()=>p(s()):()=>p(s),t={navigated:!1,pausedTurnNavigated:!1,depth:0,runId:0,ourSendPending:!1},i=()=>e.getRegisteredFunctions().some(n=>n.name===a().pageStateFunctionName),g=n=>new Promise(o=>{let l=!1;const r=N=>{l||(l=!0,clearTimeout(S),e.off("context:changed",u),o(N))},v=()=>setTimeout(()=>r(n===t.runId&&i()),a().settleMs),u=()=>{if(n!==t.runId)return r(!1);i()&&(e.off("context:changed",u),v())},S=setTimeout(()=>r(!1),a().readinessTimeoutMs);i()?v():e.on("context:changed",u)}),P=async n=>{const o=++t.runId;if(!(!await g(o)||o!==t.runId)){t.depth+=1,t.ourSendPending=!0;try{await e.sendMessage(a().continuationPrompt,{conversationId:n,hidden:!0})}catch{t.ourSendPending=!1}}},d=n=>{a().navigationFunctions.includes(n.functionName)&&(t.navigated=!0)},T=e.registerResumeGate(async()=>{a().enabled&&t.pausedTurnNavigated&&(t.pausedTurnNavigated=!1,await g(++t.runId))}),f=()=>{t.pausedTurnNavigated=t.navigated,t.navigated=!1},c=()=>{t.ourSendPending||(t.depth=0,t.runId+=1)},h=n=>{t.ourSendPending=!1;const o=t.navigated;t.navigated=!1,a().enabled&&o&&(t.depth>=a().maxDepth||P(n.conversationId))},m=()=>{t.ourSendPending=!1};return e.on("function:invoke",d),e.on("message:start",c),e.on("message:waiting-client",f),e.on("message:complete",h),e.on("message:error",m),()=>{t.runId+=1,T(),e.off("function:invoke",d),e.off("message:start",c),e.off("message:waiting-client",f),e.off("message:complete",h),e.off("message:error",m)}}Object.defineProperty(exports,"attachAutoContinueAfterNavigation",{enumerable:!0,get:function(){return w}});
@@ -1 +1 @@
1
- const d=require("./createFormCollector-DHT1ObOb.cjs");var f="ago_widget_id",g="ago_last_thread",y=7200*1e3;function v(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{const r=Math.floor(Math.random()*16);return(e==="x"?r:r&3|8).toString(16)})}function _(e={}){const r=e.key??f,i=e.threadKey??g,u=e.ttlMs??y,l=e.storage??(typeof localStorage<"u"?localStorage:void 0);let n=e.widgetId??"";if(!n&&l)try{n=l.getItem(r)??""}catch{}if(n||(n=v()),l)try{l.setItem(r,n)}catch{}const o=d.createStore({value:null,lastMessageAt:null},{key:i,storage:l}),c=o.get();c.value!==null&&s(c.lastMessageAt)&&o.set({value:null,lastMessageAt:null});function s(t){return t===null?!0:Number.isFinite(u)?Date.now()-t>u:!1}return{widgetId:n,key:r,getLastActiveThread(){const{value:t,lastMessageAt:a}=o.get();return t===null||s(a)?null:t},setActiveThread(t,a){const x=a==null?null:a instanceof Date?a.getTime():a;o.set({value:t,lastMessageAt:x})},clear(){o.set({value:null,lastMessageAt:null})}}}Object.defineProperty(exports,"createConversationSession",{enumerable:!0,get:function(){return _}});
1
+ const d=require("./createFormCollector-1GKKwQV_.cjs");var f="ago_widget_id",g="ago_last_thread",y=7200*1e3;function v(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{const r=Math.floor(Math.random()*16);return(e==="x"?r:r&3|8).toString(16)})}function _(e={}){const r=e.key??f,i=e.threadKey??g,u=e.ttlMs??y,l=e.storage??(typeof localStorage<"u"?localStorage:void 0);let n=e.widgetId??"";if(!n&&l)try{n=l.getItem(r)??""}catch{}if(n||(n=v()),l)try{l.setItem(r,n)}catch{}const o=d.createStore({value:null,lastMessageAt:null},{key:i,storage:l}),c=o.get();c.value!==null&&s(c.lastMessageAt)&&o.set({value:null,lastMessageAt:null});function s(t){return t===null?!0:Number.isFinite(u)?Date.now()-t>u:!1}return{widgetId:n,key:r,getLastActiveThread(){const{value:t,lastMessageAt:a}=o.get();return t===null||s(a)?null:t},setActiveThread(t,a){const x=a==null?null:a instanceof Date?a.getTime():a;o.set({value:t,lastMessageAt:x})},clear(){o.set({value:null,lastMessageAt:null})}}}Object.defineProperty(exports,"createConversationSession",{enumerable:!0,get:function(){return _}});
@@ -1,4 +1,4 @@
1
- import { i as d } from "./createFormCollector-F3YJfsbg.js";
1
+ import { i as d } from "./createFormCollector-DYh90kiG.js";
2
2
  var f = "ago_widget_id", g = "ago_last_thread", y = 7200 * 1e3;
3
3
  function v() {
4
4
  return typeof crypto < "u" && typeof crypto.randomUUID == "function" ? crypto.randomUUID() : "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (e) => {
@@ -0,0 +1 @@
1
+ const w=require("./AgoClient-5VGybmvz.cjs");function A(n,e){const a=e?e.storage??(typeof localStorage<"u"?localStorage:void 0):void 0;let o=n;if(e&&a)try{const m=a.getItem(e.key);m!=null&&(o=JSON.parse(m))}catch{}const s=new Set,c=()=>s.forEach(m=>m(o));function b(){if(e&&a)try{a.setItem(e.key,JSON.stringify(o))}catch{}}return{get:()=>o,set:m=>{o=m,b(),c()},subscribe:m=>(s.add(m),()=>{s.delete(m)})}}var W=/^[a-zA-Z0-9_-]{1,40}$/,I=n=>n==null||n==="";function C(n,e){if("anyOf"in n)return n.anyOf.some(c=>C(c,e));if("allOf"in n)return n.allOf.every(c=>C(c,e));const a=e[n.property];if(I(a))return!1;if(Array.isArray(n.value))return n.value.some(c=>String(a)===String(c));if(!n.op)return String(a)===String(n.value);const o=Number(a),s=Number(n.value);if(Number.isNaN(o)||Number.isNaN(s))return!1;switch(n.op){case">=":return o>=s;case"<=":return o<=s;case">":return o>s;case"<":return o<s;default:return w.logger.warn(`Unknown requiredWhen op "${n.op}"; treating as not required.`),!1}}function y(n,e){const a=n.properties??{},o=new Set;for(const c of n.required??[]){const b=a[c]?.requiredWhen;(!b||C(b,e))&&o.add(c)}for(const[c,b]of Object.entries(a))b.requiredWhen&&C(b.requiredWhen,e)&&o.add(c);const s=[...o].filter(c=>I(e[c]));return{missing:s,complete:s.length===0}}function B(n){const e={};for(const[a,o]of Object.entries(n.properties??{}))e[a]={type:o.type,...o.description!=null&&{description:o.description},...o.enum&&{enum:o.enum},...o.default!==void 0&&{default:o.default}};return{type:"object",properties:e,required:[]}}function V(n){const{name:e,description:a,schema:o}=n;if(!W.test(e))throw new Error(`Invalid form collector name "${e}": must match ${W} (it becomes the update_/submit_ function names).`);const s=typeof n.submit=="string"?n.submit?{via:"client",url:n.submit}:!1:n.submit??!1;n.autoSubmit===!0&&!s&&w.logger.warn(`FormCollector "${e}": autoSubmit is ignored because no submit target is configured.`);const c=(n.autoSubmit??!0)&&!!s,b=o.properties??{},m=t=>{const r={};for(const[u,i]of Object.entries(t)){const l=b[u];if(l)if(i==null)r[u]=i;else if(l.type==="number"||l.type==="integer"){const d=typeof i=="number"?i:Number(i);r[u]=Number.isNaN(d)?i:d}else l.type==="boolean"?r[u]=typeof i=="boolean"?i:i==="true"?!0:i==="false"?!1:!!i:r[u]=i}return r},N=n.initialValues??{},f=A({values:N,submitted:!1}),F=t=>{const r=f.get(),u={...r,values:{...r.values,...t}};return f.set(u),u};let h=null;const k=(t,r)=>{h?.emitFormEvent("form:error",{name:e,values:t,error:r})};let g=null;const D=async()=>{const{values:t}=f.get(),{complete:r,missing:u}=y(o,t);if(!r)return{ok:!1,missing:u};if(!s)return{ok:!1,error:"No submit target configured for this form collector."};const i=t;try{let l;if(s.via==="client")if("handler"in s)l=await s.handler(i);else{const d=await fetch(s.url,{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify(i)});if(!d.ok){const j=`Submit failed: HTTP ${d.status}`;return k(i,j),{ok:!1,error:j}}l=await d.json().catch(()=>{})}else{if(!h)return{ok:!1,error:"Backend submit requires install(client) (or useFormCollector) first."};l=await h.submitFormCollector(e,i)}return f.set({...f.get(),submitted:!0,submitResult:l}),h?.emitFormEvent("form:submitted",{name:e,values:i,result:l}),{ok:!0,result:l}}catch(l){const d=l instanceof Error?l.message:"Submit failed";return w.logger.error(`FormCollector "${e}" submit failed:`,l),k(i,d),{ok:!1,error:d}}},$=()=>g||(g=(async()=>{try{return await D()}finally{g=null}})(),g),q=async()=>{if(!c||!s)return null;const{values:t,submitted:r}=f.get();return r||!y(o,t).complete?null:$()},O={name:`update_${e}`,description:`Fill or update fields of the "${e}" form. ${a} Pass any subset of fields; call it repeatedly to fill the form as the user provides information. Returns the current values and which required fields are still missing.`,parameters:B(o),handler:async t=>{const r=F(m(t)),{missing:u}=y(o,r.values),i=await q();return i?i.ok?{ok:!0,values:r.values,missing:u,submitted:!0}:{ok:!0,values:r.values,missing:u,submitted:!1,submitError:i.error}:{ok:!0,values:r.values,missing:u}}},p=[O];s&&!c&&p.push({name:`submit_${e}`,description:`Submit the completed "${e}" form. Only call this once every required field is collected and the user has confirmed. If fields are missing it returns them instead of submitting.`,parameters:{type:"object",properties:{}},handler:()=>$()});const J="client__",_=s?`submit_${e}`:null,R=t=>{const r=t.functionName??t.toolName;if(r)return r.startsWith(J)?r.slice(8):r},P=t=>{let r={...N},u=!1;for(const i of t){const l=R(i);l===O.name?i.arguments&&(r={...r,...m(i.arguments)}):_&&l===_&&i.status?.toLowerCase()==="done"&&(u=!0)}f.set({values:r,submitted:u})},v=`form:${e}`,S=`${v}:definition`,x=()=>({name:`Form definition: ${e}`,description:`${a} Some fields are conditionally required; the requiredWhen field in the schema tells you when each becomes required. The form schema is the following: ${JSON.stringify(o)}.`,stable:!0}),E=()=>{const{values:t,submitted:r}=f.get(),{missing:u,complete:i}=y(o,t),l=s?c?" The form is submitted automatically as soon as every required field is filled, so there is no submit function to call.":` When nothing is missing and the user confirms, call submit_${e}.`:"",d=r?`The "${e}" form has been submitted.`:`You are currently collecting information from the user to fill the "${e}" form.`;return{name:`Form: ${e}`,description:`${d} The form's schema and field requirements are in the "${S}" client context. Call update_${e} with any fields the user provides; ask only for what is still missing.${l}`,data:{values:t,missing:u,complete:i,submitted:r}}},T=t=>{P((t.messages??[]).flatMap(r=>r.toolCalls??[]))};return{name:e,store:f,functions:p,contextKey:v,contextProvider:E,definitionContextKey:S,definitionContextProvider:x,install:t=>{h=t;for(const u of p)t.register(u);t.addDynamicContext(S,x),t.addDynamicContext(v,E);const r=f.subscribe(()=>t.notifyContextChanged());return t.on("conversation:loaded",T),()=>{r();for(const u of p)t.unregisterFunction(u.name);t.removeDynamicContext(v),t.removeDynamicContext(S),t.off("conversation:loaded",T),h===t&&(h=null)}},hydrate:P,submit:$,getValues:()=>f.get().values,setValues:t=>{F(m(t)),q()},reset:()=>{f.set({values:N,submitted:!1})},getStatus:()=>y(o,f.get().values)}}async function L(n,e){const a=await n.getFormCollector(e.name);return V({name:a.name,description:e.description??a.description,schema:e.schema??a.schema,submit:e.submit??a.submit,initialValues:e.initialValues,autoSubmit:e.autoSubmit??a.autoSubmit})}Object.defineProperty(exports,"createFormCollector",{enumerable:!0,get:function(){return V}});Object.defineProperty(exports,"createStore",{enumerable:!0,get:function(){return A}});Object.defineProperty(exports,"deriveFormStatus",{enumerable:!0,get:function(){return y}});Object.defineProperty(exports,"loadFormCollector",{enumerable:!0,get:function(){return L}});