@fiodos/web-core 0.1.10 → 0.1.12

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 (41) hide show
  1. package/dist/cjs/api/backendClient.js +20 -0
  2. package/dist/cjs/config/types.d.ts +24 -0
  3. package/dist/cjs/config/types.js +6 -1
  4. package/dist/cjs/controller/AgentController.d.ts +105 -2
  5. package/dist/cjs/controller/AgentController.js +572 -75
  6. package/dist/cjs/dropin/createFiodosAgent.d.ts +5 -0
  7. package/dist/cjs/dropin/createFiodosAgent.js +7 -0
  8. package/dist/cjs/index.d.ts +3 -3
  9. package/dist/cjs/index.js +2 -1
  10. package/dist/cjs/orb/mountOrb.d.ts +6 -0
  11. package/dist/cjs/orb/mountOrb.js +229 -33
  12. package/dist/cjs/orb/orbView.d.ts +2 -0
  13. package/dist/cjs/orb/publishedConfig.d.ts +18 -0
  14. package/dist/cjs/orb/publishedConfig.js +6 -0
  15. package/dist/cjs/speech/bubbleDictation.d.ts +11 -0
  16. package/dist/cjs/speech/bubbleDictation.js +88 -0
  17. package/dist/cjs/ui/messages.d.ts +15 -0
  18. package/dist/cjs/ui/messages.js +12 -0
  19. package/dist/cjs/version.d.ts +1 -1
  20. package/dist/cjs/version.js +1 -1
  21. package/dist/esm/api/backendClient.js +20 -0
  22. package/dist/esm/config/types.d.ts +24 -0
  23. package/dist/esm/config/types.js +5 -0
  24. package/dist/esm/controller/AgentController.d.ts +105 -2
  25. package/dist/esm/controller/AgentController.js +574 -77
  26. package/dist/esm/dropin/createFiodosAgent.d.ts +5 -0
  27. package/dist/esm/dropin/createFiodosAgent.js +7 -0
  28. package/dist/esm/index.d.ts +3 -3
  29. package/dist/esm/index.js +1 -1
  30. package/dist/esm/orb/mountOrb.d.ts +6 -0
  31. package/dist/esm/orb/mountOrb.js +230 -34
  32. package/dist/esm/orb/orbView.d.ts +2 -0
  33. package/dist/esm/orb/publishedConfig.d.ts +18 -0
  34. package/dist/esm/orb/publishedConfig.js +6 -0
  35. package/dist/esm/speech/bubbleDictation.d.ts +11 -0
  36. package/dist/esm/speech/bubbleDictation.js +84 -0
  37. package/dist/esm/ui/messages.d.ts +15 -0
  38. package/dist/esm/ui/messages.js +12 -0
  39. package/dist/esm/version.d.ts +1 -1
  40. package/dist/esm/version.js +1 -1
  41. package/package.json +2 -2
@@ -119,6 +119,21 @@ function createFiodosBackendClient(options) {
119
119
  if (request.sessionId?.trim()) {
120
120
  body.session_id = request.sessionId.trim();
121
121
  }
122
+ // Autonomous-chain continuation metadata (backward compatible: absent on a
123
+ // normal turn; an old backend simply ignores these fields).
124
+ if (request.isContinuation) {
125
+ body.is_continuation = true;
126
+ if (typeof request.chainStep === 'number')
127
+ body.chain_step = request.chainStep;
128
+ if (request.lastStep) {
129
+ body.last_step = {
130
+ type: request.lastStep.type,
131
+ intent: request.lastStep.intent,
132
+ ...(request.lastStep.label ? { label: request.lastStep.label } : {}),
133
+ success: request.lastStep.success,
134
+ };
135
+ }
136
+ }
122
137
  const res = await fetchWithTimeout(`${baseUrl}/assistant/chat`, { method: 'POST', headers: buildHeaders(), body: JSON.stringify(body) }, turnTimeoutMs, opts?.signal);
123
138
  if (!res.ok)
124
139
  throw await errorFromResponse(res);
@@ -129,11 +144,16 @@ function createFiodosBackendClient(options) {
129
144
  catch {
130
145
  throw new errors_1.AgentApiError('invalid_response');
131
146
  }
147
+ // Chain-continuation signal. Default to 'complete' so an old backend that
148
+ // never sends it keeps the one-action-per-turn behaviour (no chaining).
149
+ const rawStatus = typeof data.task_status === 'string' ? data.task_status : '';
150
+ const taskStatus = rawStatus === 'in_progress' || rawStatus === 'blocked' ? rawStatus : 'complete';
132
151
  return {
133
152
  reply: (data.reply ?? '').trim(),
134
153
  audioBase64: data.audio_base64 ?? null,
135
154
  action: (0, core_1.parseAgentAction)(data.action),
136
155
  wasTruncated: data.was_truncated === true,
156
+ taskStatus,
137
157
  };
138
158
  },
139
159
  async previewTts(voice, text) {
@@ -17,6 +17,22 @@ export interface AgentTimings {
17
17
  minTranscriptChars: number;
18
18
  }
19
19
  export declare const DEFAULT_AGENT_TIMINGS: AgentTimings;
20
+ /**
21
+ * Autonomous multi-step chaining. OFF by default: with `enabled: false` the orb
22
+ * behaves exactly as before (one action per turn). When ON, after a successful
23
+ * navigate/execute whose backend `task_status` is "in_progress", the orb takes
24
+ * the next step on its own — capped at `maxSteps` and guarded by no-progress
25
+ * detection and sensitive-confirmation pauses (which always require the human).
26
+ */
27
+ export interface AgentChaining {
28
+ /** Master switch. Default false (retrocompatible, one action per turn). */
29
+ enabled: boolean;
30
+ /** Hard cap on steps per user request (safety). Default 6. */
31
+ maxSteps: number;
32
+ /** Pause between chained steps so the user can see each screen (ms). */
33
+ dwellMs: number;
34
+ }
35
+ export declare const DEFAULT_AGENT_CHAINING: AgentChaining;
20
36
  export type TurnGateVerdict = {
21
37
  ok: true;
22
38
  } | {
@@ -40,6 +56,12 @@ export interface FiodosWebAgentConfig {
40
56
  telemetry?: TelemetryAdapter;
41
57
  /** Host auth check, required by manifest actions declaring requiresAuth. */
42
58
  isAuthenticated?: () => boolean;
59
+ /**
60
+ * Host end-user identity. Conversation memory is namespaced per identity
61
+ * (hashed LOCALLY, never sent by this module): logout/account switches swap
62
+ * to that identity's own conversation instead of leaking the previous one.
63
+ */
64
+ getUserId?: () => string | null;
43
65
  messages?: {
44
66
  catalogs?: Record<string, MessageCatalog>;
45
67
  overrides?: Partial<AgentMessages>;
@@ -59,5 +81,7 @@ export interface FiodosWebAgentConfig {
59
81
  ttsVoice?: string | (() => string | undefined);
60
82
  consentVersion?: number;
61
83
  timings?: Partial<AgentTimings>;
84
+ /** Autonomous multi-step chaining. OFF unless explicitly enabled. */
85
+ chaining?: Partial<AgentChaining>;
62
86
  }
63
87
  export type { WebUiMessages };
@@ -1,9 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFAULT_AGENT_TIMINGS = void 0;
3
+ exports.DEFAULT_AGENT_CHAINING = exports.DEFAULT_AGENT_TIMINGS = void 0;
4
4
  exports.DEFAULT_AGENT_TIMINGS = {
5
5
  thinkingWatchdogMs: 25000,
6
6
  maxListeningSeconds: 60,
7
7
  confirmationVoiceWindowMs: 8000,
8
8
  minTranscriptChars: 2,
9
9
  };
10
+ exports.DEFAULT_AGENT_CHAINING = {
11
+ enabled: false,
12
+ maxSteps: 6,
13
+ dwellMs: 450,
14
+ };
@@ -23,6 +23,19 @@ export interface AgentExchange {
23
23
  userText: string;
24
24
  replyText: string;
25
25
  }
26
+ /**
27
+ * REAL live activity for the chat panel — what the agent is actually doing
28
+ * right now, not a canned walk-through. Emitted at true lifecycle moments:
29
+ * request in flight ('thinking'), a navigate/execute action that really ran
30
+ * ('navigating'/'executing' with the manifest label), or a sensitive action
31
+ * waiting for the human ('waiting_confirmation'). Cleared when the final
32
+ * reply lands, so the panel narrative disappears exactly like before.
33
+ */
34
+ export interface AgentActivity {
35
+ kind: 'thinking' | 'navigating' | 'executing' | 'waiting_confirmation';
36
+ /** Manifest label (route/action) for navigating/executing steps. */
37
+ label?: string;
38
+ }
26
39
  /** The reactive snapshot every framework binding renders. */
27
40
  export interface AgentState {
28
41
  phase: AgentPhase;
@@ -33,6 +46,12 @@ export interface AgentState {
33
46
  isBusy: boolean;
34
47
  isListening: boolean;
35
48
  lastExchange: AgentExchange | null;
49
+ /** Paged window of recent user+reply pairs while session memory is active. */
50
+ recentExchanges: AgentExchange[];
51
+ /** Older messages exist beyond the mounted window (scroll up to load them). */
52
+ hasOlderExchanges: boolean;
53
+ /** An older page is being loaded (show the loading row at the top). */
54
+ loadingOlderExchanges: boolean;
36
55
  /** Confirmation question to show in the modal, or null. */
37
56
  confirmationMessage: string | null;
38
57
  /** Visible-only hint for strict actions (the exact phrase), or null. */
@@ -40,6 +59,10 @@ export interface AgentState {
40
59
  consentModalVisible: boolean;
41
60
  /** Mic denied/unusable: the orb should fall back to the keyboard channel. */
42
61
  voiceBlocked: boolean;
62
+ /** Current REAL agent activity for the panel's live row (null when idle). */
63
+ liveActivity: AgentActivity | null;
64
+ /** An autonomous chain is running steps (keeps the live row visible between turns). */
65
+ chainActive: boolean;
43
66
  }
44
67
  export declare class AgentController {
45
68
  readonly config: FiodosWebAgentConfig;
@@ -52,6 +75,7 @@ export declare class AgentController {
52
75
  private readonly consent;
53
76
  private readonly executor;
54
77
  private readonly timings;
78
+ private readonly chaining;
55
79
  private readonly ttsLocale;
56
80
  private readonly speech;
57
81
  private readonly notifyError;
@@ -65,7 +89,7 @@ export declare class AgentController {
65
89
  private consentModalVisible;
66
90
  private readonly sessionId;
67
91
  private sessionStarted;
68
- private readonly conversation;
92
+ private conversation;
69
93
  private pending;
70
94
  private confirmationReasked;
71
95
  private confirmationVoiceActive;
@@ -77,10 +101,52 @@ export declare class AgentController {
77
101
  private speakTimer;
78
102
  private serverTtsUnavailable;
79
103
  private pendingConsentIntent;
104
+ /** Parked chain state (set when a chain pauses on a sensitive action). */
105
+ private chainState;
106
+ /** REAL live activity for the panel (replaces the old canned walk-through). */
107
+ private liveActivity;
108
+ private chainActive;
109
+ /** How many exchanges the bubble currently mounts (grows one page at a time). */
110
+ private bubbleWindowSize;
111
+ /** Idle retention from the dashboard (undefined = 30-minute default). */
112
+ private conversationOptions;
113
+ /** Raw dashboard retention (minutes; 0 = never; null = default). Persisted
114
+ * with the session so a restore applies the same expiry rule. */
115
+ private conversationRetentionMinutes;
116
+ /** Persistence scope: internal orbs keep their memory under a separate key
117
+ * so a public orb sharing the same appId can never read it. */
118
+ private conversationScope;
119
+ /** Current identity segment (LOCAL hash of the host's getUserId; never sent
120
+ * anywhere). The conversation belongs to (app, scope, identity). */
121
+ private conversationIdentity;
122
+ private removeIdentityListeners;
123
+ private loadingOlderExchanges;
124
+ private loadOlderTimer;
80
125
  private readonly listeners;
81
126
  private unsubscribeSpeech;
82
127
  constructor(config: FiodosWebAgentConfig);
128
+ private restorePersistedConversation;
129
+ private persistConversation;
130
+ /**
131
+ * Re-evaluates the host identity and, when it changed, swaps conversations:
132
+ * the outgoing identity's session is saved under ITS private key (so a user
133
+ * who logs back in recovers it, honouring "never clear"), all in-memory
134
+ * state and UI are wiped, and the incoming identity's own session (usually
135
+ * empty) is restored. An anonymous visitor after a logout always starts
136
+ * clean — the previous user's transcript is never inherited.
137
+ */
138
+ private syncConversationIdentity;
139
+ /**
140
+ * Wipes the CURRENT identity's conversation: live memory, panel and the
141
+ * persisted blob. Hosts can call it from their logout for a hard wipe (by
142
+ * default a logout only parks the conversation under the user's private
143
+ * local key).
144
+ */
145
+ resetConversation(): void;
83
146
  getState(): AgentState;
147
+ /** Update the REAL live activity and re-render (no-op when unchanged). */
148
+ private setActivity;
149
+ private setChainActive;
84
150
  /** Whether speech recognition can actually run (API present AND mic not denied). */
85
151
  get voiceAvailable(): boolean;
86
152
  /** Unlock audio playback inside a user gesture (orb tap) so the spoken reply
@@ -90,6 +156,22 @@ export declare class AgentController {
90
156
  /** Flag the mic as denied/unusable (called on a permission error or upfront
91
157
  * permission detection) so the orb routes taps to the keyboard instead. */
92
158
  markVoiceBlocked(blocked: boolean): void;
159
+ /**
160
+ * Page one more block of older session messages into the bubble (scroll-to-top).
161
+ * The mount is deferred behind a short loading state so old messages stream in
162
+ * on demand instead of all rendering at once (keeps the open bubble light).
163
+ */
164
+ loadOlderExchanges(): void;
165
+ /**
166
+ * Apply the dashboard's context-retention setting (minutes; 0 = never clear,
167
+ * null/undefined = the 30-minute default). Called when the published config
168
+ * arrives/refreshes, so the developer's choice is live without a reload.
169
+ * `expandedMemory` = INTERNAL orb profile: use the expanded conversation
170
+ * memory window (more literal turns + longer rolling summary per request).
171
+ */
172
+ setConversationRetention(minutes?: number | null, expandedMemory?: boolean): void;
173
+ /** Collapse the bubble history back to the initial page (bubble closed). */
174
+ resetBubbleWindow(): void;
93
175
  subscribe(listener: (state: AgentState) => void): () => void;
94
176
  private emit;
95
177
  setEnabled(value: boolean): void;
@@ -109,6 +191,22 @@ export declare class AgentController {
109
191
  confirmPendingAction(): Promise<void>;
110
192
  cancelPendingAction(): void;
111
193
  private handleConfirmationTranscript;
194
+ private routeLabel;
195
+ private actionLabel;
196
+ /**
197
+ * Resolve ONE backend turn into user-facing reply/audio: run its action (or
198
+ * stage its confirmation), emit telemetry, and report whether the autonomous
199
+ * chain may take another step. Shared by the first turn and every
200
+ * continuation so both follow the exact same security path — disabled
201
+ * capabilities, confidentiality and sensitive confirmations apply per step.
202
+ */
203
+ private applyOutcome;
204
+ /**
205
+ * The autonomous continuation loop. Extracted so confirmPendingAction can
206
+ * RESUME the SAME chain after a sensitive step is confirmed. Capped at
207
+ * maxSteps, with no-progress detection and sensitive-confirmation pauses.
208
+ */
209
+ private runChainLoop;
112
210
  private handleTranscript;
113
211
  private onTranscript;
114
212
  private onSpeechError;
@@ -119,7 +217,12 @@ export declare class AgentController {
119
217
  }): Promise<void>;
120
218
  acceptConsent(): Promise<void>;
121
219
  declineConsent(): void;
122
- cancelAll(): void;
220
+ /**
221
+ * Cancel everything in flight. If a first turn was still awaiting its reply,
222
+ * its message is removed from the panel and returned here so the UI can put
223
+ * it back into the input for editing; null otherwise.
224
+ */
225
+ cancelAll(): string | null;
123
226
  /** Best-effort backend warm-up (cold-start mitigation). */
124
227
  warmUp(): void;
125
228
  dispose(): void;