@formio/uag-js 0.0.0-stage → 2.0.0-rc.1

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/LICENSE.txt ADDED
@@ -0,0 +1,19 @@
1
+ The MIT License (MIT)
2
+ Copyright (c) 2025 Form.io
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ this software and associated documentation files (the "Software"), to deal in the
6
+ Software without restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
8
+ Software, and to permit persons to whom the Software is furnished to do so,
9
+ subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15
+ INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16
+ PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,34 @@
1
- # Temporary Holding Version
1
+ # @formio/uag-js
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The [Form.io UAG](https://ai.form.io/developers) for formio.js applications. Register it once, and forms tagged `uag` save through the UAG (so their "Agent: Run task" actions run), and those whose task has an input get **Agent Input**, which fills the form from what the user describes without overwriting what they entered. Every other form, and every other request, goes to Form.io as before. Any `uag` form can also be rendered as a [chat](#chat).
4
+
5
+ ```js
6
+ import { Formio } from '@formio/js';
7
+ import { UAG } from '@formio/uag-js';
8
+ import '@formio/uag-js/uag-js.css';
9
+
10
+ Formio.setProjectUrl('https://forms.example.com/myproject');
11
+ Formio.use(UAG('https://uag.example.com'));
12
+
13
+ Formio.createForm(document.getElementById('claim'), 'https://forms.example.com/myproject/claim');
14
+ ```
15
+
16
+ Requests to the UAG carry the user's Form.io token (`x-jwt-token`), as formio.js sends it to Form.io; no other token is needed. Routing in the browser is not a security boundary: protect the fields an agent owns on the server, with an agent role, form permissions and `uagAuthoritative`.
17
+
18
+ ## Chat
19
+
20
+ Any form tagged `uag` can also be rendered as a chat, the way `Formio.createForm` renders it as a form. A person describes what they need; the chat asks for what is still missing and fills the form behind it, which validates and submits through the UAG once they confirm. Each turn is the form's `{form}/agent/chat` on the UAG, so there is no model code and no server of your own, and it needs no Agentic Formflow license (the UAG needs an agent engine).
21
+
22
+ ```js
23
+ Formio.use(UAG('https://uag.example.com'));
24
+
25
+ const chat = await Formio.createChat(document.getElementById('help'), 'https://forms.example.com/myproject/servicerequest', {
26
+ suggestions: ['My internet is down'],
27
+ markdown: (text) => marked.parse(text) // optional; the output is sanitized
28
+ });
29
+ chat.on('submitDone', (submission) => console.log('Saved', submission._id));
30
+ ```
31
+
32
+ `createChat` is also exported (and `FormioUAG.createChat` with script tags). The chat renders through formio.js templates (`uagChat`, `uagChatMessage`, …) you can replace per framework or per chat, translates through `i18n`, and is themed with `--uag-chat-*` CSS properties in `uag-js.css`.
33
+
34
+ Documentation: [JavaScript (formio.js)](https://ai.form.io/developers/renderer) · [Chat widget](https://ai.form.io/developers/chat).
package/index.d.ts ADDED
@@ -0,0 +1,231 @@
1
+ // Types for @formio/uag-js.
2
+
3
+ /** One field's result from the form's agent operations. */
4
+ export interface FieldResult {
5
+ path: string;
6
+ status: 'confident' | 'uncertain' | 'suggested' | 'missing' | string;
7
+ confidence?: number;
8
+ alternatives?: { label: string; value: unknown; confidence: number }[];
9
+ [key: string]: unknown;
10
+ }
11
+
12
+ /** A `result` event: one engine group's fields, and the values to apply. */
13
+ export interface ResultEvent {
14
+ kind: 'decision' | 'value' | string;
15
+ task?: string;
16
+ engine?: string;
17
+ fields: Record<string, FieldResult>;
18
+ patch: Record<string, unknown>;
19
+ error?: string;
20
+ [key: string]: unknown;
21
+ }
22
+
23
+ /** An error reported while filling in; `event` is the stream's `error` event, when it came from one. */
24
+ export interface AgentInputError extends Error {
25
+ event?: { kind?: string; task?: string; error?: string; attempts?: number; requestId?: string };
26
+ }
27
+
28
+ export interface AttachOptions {
29
+ /** The task to run (the `uag` value). Default: the task of the input that triggered it. */
30
+ task?: string;
31
+ /** When to extract. Default `blur`; `next` for wizards. */
32
+ trigger?: 'blur' | 'pause' | 'next' | 'button';
33
+ /** The UAG's URL, when not the one given to `UAG()`. */
34
+ uagUrl?: string;
35
+ /** Where the form's agent operations are, such as a relay of your own (`{formUrl}/agent/extract`). */
36
+ formUrl?: string;
37
+ pauseMs?: number;
38
+ nextTimeoutMs?: number;
39
+ /**
40
+ * Require the user to check every uncertain value before the wizard moves
41
+ * on or the form submits: they change it, or tick "Yes, this looks right"
42
+ * on its note, which then turns `uag-reviewed`. Default `false`.
43
+ */
44
+ requireReview?: boolean;
45
+ fetch?: typeof fetch;
46
+ onStart?: (info: { followUp: boolean }) => void;
47
+ onResult?: (event: ResultEvent) => void;
48
+ onError?: (error: AgentInputError) => void;
49
+ onDone?: (summary: Record<string, any> | null, info: { followUp: boolean }) => void;
50
+ }
51
+
52
+ export interface ExtractionRun {
53
+ /** Resolves when the first decision results are applied, or the request ends. */
54
+ decided: Promise<void>;
55
+ /** Resolves when the request, and any follow-up, is done. Failures are reported, never rejected. */
56
+ done: Promise<void>;
57
+ }
58
+
59
+ export declare class ExtractionState {
60
+ agentValues: Record<string, unknown>;
61
+ userEdited: Record<string, boolean>;
62
+ canApply(path: string, currentValue: unknown): boolean;
63
+ recordAgent(path: string, value: unknown): void;
64
+ recordUser(path: string): void;
65
+ source(path: string): 'user' | 'agent' | 'none';
66
+ }
67
+
68
+ export declare class SSEParser {
69
+ constructor(onEvent: (name: string, data: any) => void);
70
+ push(chunk: string): void;
71
+ }
72
+
73
+ export interface AgentInput {
74
+ extract(): ExtractionRun;
75
+ state: ExtractionState;
76
+ detach(): void;
77
+ }
78
+
79
+ /** One message of a chat's conversation. */
80
+ export interface ChatMessage {
81
+ role: 'user' | 'assistant';
82
+ content: string;
83
+ }
84
+
85
+ /** A field the chat could not collect yet; the person finishes it in the form. */
86
+ export interface ChatUnsupportedField {
87
+ path: string;
88
+ label: string;
89
+ required: boolean;
90
+ empty: boolean;
91
+ }
92
+
93
+ /** The UAG's answer to one turn of a form's chat (`POST {form}/agent/chat`). */
94
+ export interface ChatTurnResponse {
95
+ requestId?: string;
96
+ /** The assistant's next message. */
97
+ reply: string;
98
+ /** The values accepted this turn, by data path. */
99
+ patch: Record<string, unknown>;
100
+ /** The form's data with `patch` applied. */
101
+ data: Record<string, unknown>;
102
+ /** Each value the engine gave this turn: `suggested` (accepted) or `invalid` (with `error`). */
103
+ fields: Record<string, { path: string; label: string; status: 'suggested' | 'invalid'; value: unknown; error?: string }>;
104
+ errors: { path: string; label?: string; error: string }[];
105
+ remaining: {
106
+ required: { path: string; label: string }[];
107
+ optional: { path: string; label: string }[];
108
+ unsupported: ChatUnsupportedField[];
109
+ };
110
+ /** Every required field is filled and valid: the form can be submitted. */
111
+ complete: boolean;
112
+ /** The person confirmed the summary they were shown, and nothing changed. */
113
+ confirmed: boolean;
114
+ engine: {
115
+ name: string;
116
+ model: string;
117
+ latencyMs: number;
118
+ toolCalls: { name: string; isError: boolean }[];
119
+ usage?: { inputTokens?: number | null; outputTokens?: number | null };
120
+ };
121
+ }
122
+
123
+ /** A template: an HTML string interpolated by formio.js, or a function of its context. */
124
+ export type ChatTemplate = { form: string | ((ctx: any) => string) };
125
+
126
+ /** The chat's template names, and the context each is rendered with (plus formio.js's own: `t`, `options`, …). */
127
+ export interface ChatTemplateContexts {
128
+ uagChat: { title: string; view: 'chat' | 'form'; labels: { open: string; close: string; reset: string; log: string }; log: string; composer: string; form: string };
129
+ uagChatMessage: { role: 'user' | 'assistant'; text: string; html: string };
130
+ uagChatTyping: { ariaLabel: string };
131
+ uagChatSuggestions: { suggestions: string[] };
132
+ uagChatComposer: { inputId: string; inputLabel: string; placeholder: string; sendLabel: string; maxLength: number; inactive: boolean; busy: boolean };
133
+ uagChatSummary: { title: string; rows: { label: string; value: string }[]; submitLabel: string; editLabel: string; busy: boolean };
134
+ uagChatNotice: { kind: 'info' | 'error' | 'success'; text: string };
135
+ }
136
+
137
+ /** Options of `createChat`, on top of every formio.js form option (`templates`, `i18n`, `language`, `readOnly`, `hooks`, …). */
138
+ export interface ChatOptions {
139
+ /** The UAG's URL, when not the one given to `UAG()`. */
140
+ uagUrl?: string;
141
+ /** Where to send turns instead of the form's chat on the UAG, such as a relay of your own. */
142
+ chatUrl?: string;
143
+ /** The title in the chat's header. Default: the form's title. */
144
+ title?: string;
145
+ /** The first message, shown and never sent. `{{title}}` is the form's title; `''` shows none. */
146
+ greeting?: string;
147
+ /** Messages the person can send with one click, until they send their first. */
148
+ suggestions?: string[];
149
+ placeholder?: string;
150
+ /** The summary's submit button. Default: "Submit". */
151
+ submitLabel?: string;
152
+ /** The message after a successful submission. */
153
+ submitted?: string;
154
+ /** Render a reply as HTML (for example with marked). The output is always sanitized. */
155
+ markdown?: (text: string) => string;
156
+ /** Keep the conversation and data across reloads, per form. Default: not kept. */
157
+ storage?: 'session' | 'local';
158
+ /** The most messages sent with a turn (newest first). Default: 40, the UAG's default limit. */
159
+ maxMessages?: number;
160
+ /** The composer's character limit. Default: 2000, the UAG's default limit. */
161
+ maxMessageLength?: number;
162
+ fetch?: typeof fetch;
163
+ templates?: Partial<Record<keyof ChatTemplateContexts, ChatTemplate>> & Record<string, ChatTemplate>;
164
+ [option: string]: any;
165
+ }
166
+
167
+ /** The chat: a formio.js form (a Webform) rendered as a conversation. */
168
+ export interface ChatForm {
169
+ /** The conversation so far (not the greeting or notices). */
170
+ readonly messages: ChatMessage[];
171
+ /** Send a message. Resolves with the turn's response, or null when it failed or was dropped. */
172
+ send(text: string): Promise<ChatTurnResponse | null>;
173
+ /** Start over: clear the conversation and the values the chat wrote. */
174
+ reset(): void;
175
+ /** Show the form itself, to review or edit. */
176
+ openForm(): void;
177
+ /** Return from the form to the chat. */
178
+ closeForm(): void;
179
+ /** Submit the form (through the UAG), as the summary's Submit button does. */
180
+ submitChat(): Promise<any>;
181
+ on(event: 'chatMessage', handler: (message: ChatMessage) => void): void;
182
+ on(event: 'chatReply' | 'chatComplete', handler: (response: ChatTurnResponse) => void): void;
183
+ on(event: 'chatError', handler: (error: Error & { status?: number; response?: any }) => void): void;
184
+ on(event: 'chatReset', handler: () => void): void;
185
+ on(event: string, handler: (...args: any[]) => void): void;
186
+ [member: string]: any;
187
+ }
188
+
189
+ export interface UAGOptions extends Omit<AttachOptions, 'uagUrl' | 'formUrl'> {
190
+ /** `false` attaches no Agent Input anywhere; submissions of `uag` forms still go to the UAG. */
191
+ agentInput?: boolean;
192
+ }
193
+
194
+ /** The formio.js module: `Formio.use(UAG('https://uag.example.com'))`. It also registers the `chat` display and `Formio.createChat`. */
195
+ export declare function UAG(uagUrl: string, options?: UAGOptions): (Formio: any) => { fetch: Record<string, any>; displays?: Record<string, any> };
196
+ export declare namespace UAG {
197
+ /** The same as `attach`. */
198
+ function attach(form: any, options?: AttachOptions): AgentInput;
199
+ /** The same as `createChat`. */
200
+ function createChat(element: HTMLElement, src: string | Record<string, any>, options?: ChatOptions): Promise<ChatForm>;
201
+ }
202
+
203
+ /**
204
+ * Render a form as a chat, as `Formio.createForm` renders it as a form. `src` is
205
+ * the form's Form.io URL, or a definition with its `_id`. After `UAG()` is
206
+ * registered, `Formio.createChat` is the same function.
207
+ */
208
+ export declare function createChat(element: HTMLElement, src: string | Record<string, any>, options?: ChatOptions): Promise<ChatForm>;
209
+ /** The built-in chat templates, by name. */
210
+ export declare const CHAT_TEMPLATES: Record<keyof ChatTemplateContexts, ChatTemplate>;
211
+
212
+ /** Attach Agent Input to a rendered form (a formio.js Webform or Wizard). */
213
+ export declare function attach(form: any, options?: AttachOptions): AgentInput;
214
+ /** A form's URL on the UAG, by id; empty when the definition has no `_id`. */
215
+ export declare function uagFormUrl(uagUrl: string, definition: { _id?: string; project?: string } | null | undefined): string;
216
+ /** The formio.js fetch plugin that sends the submission requests of `uag` forms to the UAG. */
217
+ export declare function routingPlugin(uagUrl: string): { priority: number; preRequest(args: any): void; wrapRequestPromise(promise: any, args: any): any };
218
+ export declare function isEmpty(value: unknown): boolean;
219
+
220
+ declare const uag: {
221
+ UAG: typeof UAG;
222
+ attach: typeof attach;
223
+ createChat: typeof createChat;
224
+ uagFormUrl: typeof uagFormUrl;
225
+ routingPlugin: typeof routingPlugin;
226
+ ExtractionState: typeof ExtractionState;
227
+ SSEParser: typeof SSEParser;
228
+ isEmpty: typeof isEmpty;
229
+ CHAT_TEMPLATES: typeof CHAT_TEMPLATES;
230
+ };
231
+ export default uag;