@magicx-eng/ai-autocomplete-vanilla 0.5.6 → 0.6.0

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/README.md CHANGED
@@ -374,11 +374,12 @@ Override these on the container element. All built-in defaults use `:where()` (z
374
374
  | `--aia-shadow` | `inset 0 1px 0 rgba(255,255,255,0.9), 0 1px 2px rgba(16,24,40,0.1), 0 8px 24px rgba(16,24,40,0.16)` | `inset 0 1px 0 rgba(255,255,255,0.06), 0 1px 2px rgba(0,0,0,0.4), 0 8px 24px rgba(0,0,0,0.5)` | Input container elevation (box-shadow) |
375
375
  | `--aia-dropdown-offset` | `13px` | `13px` | Gap between the input box and the dropdown (the dropdown's margin toward the input). |
376
376
  | `--aia-footer-gap` | `8px` | `8px` | Breathing room above the dropdown footer (badge / keyboard hints), additive to the dropdown's 8px section gap. |
377
+ | `--aia-footer-chip-bg` | `--aia-surface` at 65% | `--aia-surface` at 65% | Fill behind the footer's keyboard hint and AI-Autocomplete badge. The option list scrolls under the footer, so this keeps both legible over the row passing behind them. `transparent` on the glass surface. |
377
378
  | `--aia-dropdown-bg` | — | — | Optional bg color the dropdown's "glass" rim shadow tints toward. Set this to the page background behind the dropdown so the bottom-corner glow blends seamlessly. |
378
379
  | `--aia-scrollbar-thumb` | `rgba(0, 0, 0, 0.3)` | `rgba(0, 0, 0, 0.3)` | Color of the option list's scrollbar thumb (Firefox + WebKit). |
379
380
  | `--aia-streak-rgb` | `99, 102, 241` | `255, 255, 255` | Comma-separated RGB triplet used to tint the option-selection streak animation (consumed via `rgba(var(--aia-streak-rgb), …)`). |
380
381
  | `--aia-streak-glass-bg` | `rgba(99, 102, 241, 0.1)` | `rgba(255, 255, 255, 0.1)` | Background fill for the streak's glass-pill effect. |
381
- | `--aia-skeleton-bg` | `rgba(189, 189, 189, 0.51)` | `#333539` | Fill color for the loading skeleton bars and the masked text in cached pills/options. |
382
+ | `--aia-skeleton-bg` | `rgba(189, 189, 189, 0.25)` | `#1a1b1d` | Fill color for the loading skeleton bars and the masked text in cached pills/options. |
382
383
 
383
384
  ### Per-mode Overrides
384
385
 
package/dist/index.d.mts CHANGED
@@ -23,11 +23,28 @@ interface InputItem {
23
23
  type: string;
24
24
  text: string;
25
25
  state: "completed" | "in_progress";
26
+ /** Absent or "selected" = echo of client params; "identified" = LLM-inferred. */
27
+ source?: "selected" | "identified";
28
+ }
29
+ /** Wire shape for an LLM-identified param echoed back to the server. */
30
+ interface IdentifiedParam {
31
+ type: string;
32
+ value: string;
33
+ }
34
+ /**
35
+ * Wire shape for a recently-suggested hint entry: a suggestion that was on
36
+ * screen when the user started typing the current unresolved trailing text.
37
+ */
38
+ interface RecentlySuggested {
39
+ type: string;
40
+ text: string;
26
41
  }
27
42
  interface AutocompleteRequest {
28
43
  data: {
29
44
  raw_query: string;
30
45
  completed_params: CompletedParam[];
46
+ identified_params?: IdentifiedParam[];
47
+ recently_suggested?: RecentlySuggested[];
31
48
  contact_account_count?: number;
32
49
  };
33
50
  meta: {
@@ -61,6 +78,16 @@ interface CompletedParamState extends CompletedParam {
61
78
  options: SuggestionOption[];
62
79
  metadata?: Record<string, unknown>;
63
80
  }
81
+ /**
82
+ * Client-side state for an LLM-identified param. Tentative — replaced
83
+ * wholesale from each response (latest wins) and dropped when its text no
84
+ * longer matches. Never placeholder-substituted in raw_query.
85
+ */
86
+ interface IdentifiedParamState {
87
+ id: string;
88
+ type: string;
89
+ text: string;
90
+ }
64
91
  type Segment = {
65
92
  type: "text";
66
93
  value: string;
@@ -68,6 +95,10 @@ type Segment = {
68
95
  type: "completed";
69
96
  value: string;
70
97
  param: CompletedParamState;
98
+ } | {
99
+ type: "identified";
100
+ value: string;
101
+ param: IdentifiedParamState;
71
102
  };
72
103
  type AppearanceMode = "light" | "dark" | "auto";
73
104
  interface APIConfigBase {
@@ -105,6 +136,24 @@ interface AutocompleteResult {
105
136
  interface CoreInputState {
106
137
  text: string;
107
138
  completedParams: CompletedParamState[];
139
+ /**
140
+ * LLM-identified params from the latest response. Revisable: replaced
141
+ * wholesale per response, dropped when their text is edited away. Never
142
+ * override or overlap completed params.
143
+ */
144
+ identifiedParams: IdentifiedParamState[];
145
+ /**
146
+ * Open while the user has unresolved trailing text: anchored at the covered
147
+ * offset where they started typing, snapshotting the actionable suggestions
148
+ * that were on screen. While open, fetches carry `recently_suggested`
149
+ * (snapshot ∪ current on-screen suggestions). Closes when the trailing text
150
+ * becomes covered by a completed/identified param, is deleted back to the
151
+ * anchor, is consumed by an option selection, or on reset().
152
+ */
153
+ pendingSpan: {
154
+ anchor: number;
155
+ snapshot: Suggestion[];
156
+ } | null;
108
157
  suggestions: Suggestion[];
109
158
  activeDropdownIndex: number;
110
159
  newParamId: string | null;
@@ -325,6 +374,14 @@ declare class AIAutocomplete {
325
374
  /** Auto-clear newParamId after shimmer animation. */
326
375
  private subscribeNewParamTimer;
327
376
  private handleChange;
377
+ /**
378
+ * Opens the pending span on the first keystroke past covered text: there is
379
+ * unresolved trailing text beyond the covered offset (filterBase / last pill
380
+ * end), actionable suggestions are on screen, and no span is already open.
381
+ * The span snapshots those suggestions so `recently_suggested` can carry
382
+ * them even after later responses replace what's on screen.
383
+ */
384
+ private maybeOpenPendingSpan;
328
385
  /**
329
386
  * In re-edit mode, once the user has typed enough that no *tappable* options
330
387
  * still match (non-tappable options are kept by filterOptions regardless of
@@ -439,7 +496,12 @@ interface BuildQueryResult {
439
496
  * replaces each completed param's text in the string with a {{TYPE_N}} token,
440
497
  * and returns the transformed query + params with placeholders filled in.
441
498
  *
442
- * Replacements happen left-to-right, first occurrence only per param.
499
+ * Replacements advance a position cursor (params are appended in text order in
500
+ * normal flows), so a short param value (e.g. quantity "1") can never match
501
+ * INSIDE an already-inserted placeholder (e.g. the "1" in "{{SIZE_1}}") and
502
+ * splice into it. Out-of-order params fall back to a from-zero rescan that
503
+ * rejects any match overlapping a previously inserted placeholder; with no
504
+ * clean match the param is left unreplaced (same as the text-not-found path).
443
505
  * Counter is per-type (e.g. {{TASK_1}}, {{GOAL_1}}, {{GOAL_2}}).
444
506
  */
445
507
  declare function buildQuery(text: string, completedParams: CompletedParamState[]): BuildQueryResult;
@@ -474,4 +536,4 @@ declare class ModeController {
474
536
  private detachListener;
475
537
  }
476
538
 
477
- export { AIAutocomplete, type APIConfig, type APIKeyConfig, ATTRIBUTION_URL, type AccessTokenConfig, type AccessTokenResult, type AppearanceMode, type AutocompleteRequest, type AutocompleteResponse, type AutocompleteResult, type CompletedParam, type CompletedParamState, type CoreOptions, type CoreState, type InputItem, ModeController, type OptionOverrides, type RenderMode, type Segment, type Store, type Suggestion, type SuggestionOption, type TaskKind, buildAttributionUrl, buildQuery, createStore, cursorIsAtEnd, extractPlainText, getCursorOffset, getFooterHint, plainTextLength, previousGraphemeBoundary, renderEditableContent, setCursorOffset };
539
+ export { AIAutocomplete, type APIConfig, type APIKeyConfig, ATTRIBUTION_URL, type AccessTokenConfig, type AccessTokenResult, type AppearanceMode, type AutocompleteRequest, type AutocompleteResponse, type AutocompleteResult, type CompletedParam, type CompletedParamState, type CoreOptions, type CoreState, type IdentifiedParam, type IdentifiedParamState, type InputItem, ModeController, type OptionOverrides, type RecentlySuggested, type RenderMode, type Segment, type Store, type Suggestion, type SuggestionOption, type TaskKind, buildAttributionUrl, buildQuery, createStore, cursorIsAtEnd, extractPlainText, getCursorOffset, getFooterHint, plainTextLength, previousGraphemeBoundary, renderEditableContent, setCursorOffset };
package/dist/index.d.ts CHANGED
@@ -23,11 +23,28 @@ interface InputItem {
23
23
  type: string;
24
24
  text: string;
25
25
  state: "completed" | "in_progress";
26
+ /** Absent or "selected" = echo of client params; "identified" = LLM-inferred. */
27
+ source?: "selected" | "identified";
28
+ }
29
+ /** Wire shape for an LLM-identified param echoed back to the server. */
30
+ interface IdentifiedParam {
31
+ type: string;
32
+ value: string;
33
+ }
34
+ /**
35
+ * Wire shape for a recently-suggested hint entry: a suggestion that was on
36
+ * screen when the user started typing the current unresolved trailing text.
37
+ */
38
+ interface RecentlySuggested {
39
+ type: string;
40
+ text: string;
26
41
  }
27
42
  interface AutocompleteRequest {
28
43
  data: {
29
44
  raw_query: string;
30
45
  completed_params: CompletedParam[];
46
+ identified_params?: IdentifiedParam[];
47
+ recently_suggested?: RecentlySuggested[];
31
48
  contact_account_count?: number;
32
49
  };
33
50
  meta: {
@@ -61,6 +78,16 @@ interface CompletedParamState extends CompletedParam {
61
78
  options: SuggestionOption[];
62
79
  metadata?: Record<string, unknown>;
63
80
  }
81
+ /**
82
+ * Client-side state for an LLM-identified param. Tentative — replaced
83
+ * wholesale from each response (latest wins) and dropped when its text no
84
+ * longer matches. Never placeholder-substituted in raw_query.
85
+ */
86
+ interface IdentifiedParamState {
87
+ id: string;
88
+ type: string;
89
+ text: string;
90
+ }
64
91
  type Segment = {
65
92
  type: "text";
66
93
  value: string;
@@ -68,6 +95,10 @@ type Segment = {
68
95
  type: "completed";
69
96
  value: string;
70
97
  param: CompletedParamState;
98
+ } | {
99
+ type: "identified";
100
+ value: string;
101
+ param: IdentifiedParamState;
71
102
  };
72
103
  type AppearanceMode = "light" | "dark" | "auto";
73
104
  interface APIConfigBase {
@@ -105,6 +136,24 @@ interface AutocompleteResult {
105
136
  interface CoreInputState {
106
137
  text: string;
107
138
  completedParams: CompletedParamState[];
139
+ /**
140
+ * LLM-identified params from the latest response. Revisable: replaced
141
+ * wholesale per response, dropped when their text is edited away. Never
142
+ * override or overlap completed params.
143
+ */
144
+ identifiedParams: IdentifiedParamState[];
145
+ /**
146
+ * Open while the user has unresolved trailing text: anchored at the covered
147
+ * offset where they started typing, snapshotting the actionable suggestions
148
+ * that were on screen. While open, fetches carry `recently_suggested`
149
+ * (snapshot ∪ current on-screen suggestions). Closes when the trailing text
150
+ * becomes covered by a completed/identified param, is deleted back to the
151
+ * anchor, is consumed by an option selection, or on reset().
152
+ */
153
+ pendingSpan: {
154
+ anchor: number;
155
+ snapshot: Suggestion[];
156
+ } | null;
108
157
  suggestions: Suggestion[];
109
158
  activeDropdownIndex: number;
110
159
  newParamId: string | null;
@@ -325,6 +374,14 @@ declare class AIAutocomplete {
325
374
  /** Auto-clear newParamId after shimmer animation. */
326
375
  private subscribeNewParamTimer;
327
376
  private handleChange;
377
+ /**
378
+ * Opens the pending span on the first keystroke past covered text: there is
379
+ * unresolved trailing text beyond the covered offset (filterBase / last pill
380
+ * end), actionable suggestions are on screen, and no span is already open.
381
+ * The span snapshots those suggestions so `recently_suggested` can carry
382
+ * them even after later responses replace what's on screen.
383
+ */
384
+ private maybeOpenPendingSpan;
328
385
  /**
329
386
  * In re-edit mode, once the user has typed enough that no *tappable* options
330
387
  * still match (non-tappable options are kept by filterOptions regardless of
@@ -439,7 +496,12 @@ interface BuildQueryResult {
439
496
  * replaces each completed param's text in the string with a {{TYPE_N}} token,
440
497
  * and returns the transformed query + params with placeholders filled in.
441
498
  *
442
- * Replacements happen left-to-right, first occurrence only per param.
499
+ * Replacements advance a position cursor (params are appended in text order in
500
+ * normal flows), so a short param value (e.g. quantity "1") can never match
501
+ * INSIDE an already-inserted placeholder (e.g. the "1" in "{{SIZE_1}}") and
502
+ * splice into it. Out-of-order params fall back to a from-zero rescan that
503
+ * rejects any match overlapping a previously inserted placeholder; with no
504
+ * clean match the param is left unreplaced (same as the text-not-found path).
443
505
  * Counter is per-type (e.g. {{TASK_1}}, {{GOAL_1}}, {{GOAL_2}}).
444
506
  */
445
507
  declare function buildQuery(text: string, completedParams: CompletedParamState[]): BuildQueryResult;
@@ -474,4 +536,4 @@ declare class ModeController {
474
536
  private detachListener;
475
537
  }
476
538
 
477
- export { AIAutocomplete, type APIConfig, type APIKeyConfig, ATTRIBUTION_URL, type AccessTokenConfig, type AccessTokenResult, type AppearanceMode, type AutocompleteRequest, type AutocompleteResponse, type AutocompleteResult, type CompletedParam, type CompletedParamState, type CoreOptions, type CoreState, type InputItem, ModeController, type OptionOverrides, type RenderMode, type Segment, type Store, type Suggestion, type SuggestionOption, type TaskKind, buildAttributionUrl, buildQuery, createStore, cursorIsAtEnd, extractPlainText, getCursorOffset, getFooterHint, plainTextLength, previousGraphemeBoundary, renderEditableContent, setCursorOffset };
539
+ export { AIAutocomplete, type APIConfig, type APIKeyConfig, ATTRIBUTION_URL, type AccessTokenConfig, type AccessTokenResult, type AppearanceMode, type AutocompleteRequest, type AutocompleteResponse, type AutocompleteResult, type CompletedParam, type CompletedParamState, type CoreOptions, type CoreState, type IdentifiedParam, type IdentifiedParamState, type InputItem, ModeController, type OptionOverrides, type RecentlySuggested, type RenderMode, type Segment, type Store, type Suggestion, type SuggestionOption, type TaskKind, buildAttributionUrl, buildQuery, createStore, cursorIsAtEnd, extractPlainText, getCursorOffset, getFooterHint, plainTextLength, previousGraphemeBoundary, renderEditableContent, setCursorOffset };