@elizaos/plugin-form 2.0.0-beta.1 → 2.0.3-beta.3

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 (60) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +134 -0
  3. package/package.json +22 -4
  4. package/registry-entry.json +26 -0
  5. package/dist/actions/restore.d.ts +0 -25
  6. package/dist/actions/restore.d.ts.map +0 -1
  7. package/dist/actions/restore.js +0 -176
  8. package/dist/actions/restore.js.map +0 -1
  9. package/dist/builder.d.ts +0 -320
  10. package/dist/builder.d.ts.map +0 -1
  11. package/dist/builder.js +0 -458
  12. package/dist/builder.js.map +0 -1
  13. package/dist/builtins.d.ts +0 -128
  14. package/dist/builtins.d.ts.map +0 -1
  15. package/dist/builtins.js +0 -233
  16. package/dist/builtins.js.map +0 -1
  17. package/dist/defaults.d.ts +0 -95
  18. package/dist/defaults.d.ts.map +0 -1
  19. package/dist/defaults.js +0 -79
  20. package/dist/defaults.js.map +0 -1
  21. package/dist/evaluators/extractor.d.ts +0 -28
  22. package/dist/evaluators/extractor.d.ts.map +0 -1
  23. package/dist/evaluators/extractor.js +0 -247
  24. package/dist/evaluators/extractor.js.map +0 -1
  25. package/dist/extraction.d.ts +0 -55
  26. package/dist/extraction.d.ts.map +0 -1
  27. package/dist/extraction.js +0 -331
  28. package/dist/extraction.js.map +0 -1
  29. package/dist/index.d.ts +0 -31
  30. package/dist/index.d.ts.map +0 -1
  31. package/dist/index.js +0 -144
  32. package/dist/index.js.map +0 -1
  33. package/dist/providers/context.d.ts +0 -56
  34. package/dist/providers/context.d.ts.map +0 -1
  35. package/dist/providers/context.js +0 -206
  36. package/dist/providers/context.js.map +0 -1
  37. package/dist/service.d.ts +0 -402
  38. package/dist/service.d.ts.map +0 -1
  39. package/dist/service.js +0 -1158
  40. package/dist/service.js.map +0 -1
  41. package/dist/storage.d.ts +0 -228
  42. package/dist/storage.d.ts.map +0 -1
  43. package/dist/storage.js +0 -218
  44. package/dist/storage.js.map +0 -1
  45. package/dist/template.d.ts +0 -10
  46. package/dist/template.d.ts.map +0 -1
  47. package/dist/template.js +0 -60
  48. package/dist/template.js.map +0 -1
  49. package/dist/ttl.d.ts +0 -144
  50. package/dist/ttl.d.ts.map +0 -1
  51. package/dist/ttl.js +0 -85
  52. package/dist/ttl.js.map +0 -1
  53. package/dist/types.d.ts +0 -1213
  54. package/dist/types.d.ts.map +0 -1
  55. package/dist/types.js +0 -39
  56. package/dist/types.js.map +0 -1
  57. package/dist/validation.d.ts +0 -156
  58. package/dist/validation.d.ts.map +0 -1
  59. package/dist/validation.js +0 -289
  60. package/dist/validation.js.map +0 -1
@@ -1,247 +0,0 @@
1
- import { EvaluatorPriority, logger } from "@elizaos/core";
2
- import {
3
- buildFormExtractorPromptSection,
4
- buildFormExtractorSchema,
5
- coerceExtractionsAgainstControls,
6
- parseFormExtractorOutput
7
- } from "../extraction";
8
- import { buildTemplateValues } from "../template";
9
- async function emitEvent(runtime, eventType, payload) {
10
- if (typeof runtime.emitEvent !== "function") return;
11
- const eventPayload = { runtime, ...payload };
12
- await runtime.emitEvent(eventType, eventPayload);
13
- }
14
- async function checkAndActivateExternalField(runtime, formService, session, form, entityId, field) {
15
- const freshSession = await formService.getActiveSession(
16
- entityId,
17
- session.roomId
18
- );
19
- if (!freshSession) return;
20
- const control = form.controls.find((c) => c.key === field);
21
- if (!control || !formService.isExternalType(control.type)) return;
22
- if (!formService.areSubFieldsFilled(freshSession, field)) return;
23
- const subValues = formService.getSubFieldValues(freshSession, field);
24
- await emitEvent(runtime, "FORM_SUBCONTROLS_FILLED", {
25
- sessionId: session.id,
26
- field,
27
- subValues
28
- });
29
- const activation = await formService.activateExternalField(
30
- session.id,
31
- entityId,
32
- field
33
- );
34
- const activationPayload = JSON.parse(
35
- JSON.stringify(activation)
36
- );
37
- await emitEvent(runtime, "FORM_EXTERNAL_ACTIVATED", {
38
- sessionId: session.id,
39
- field,
40
- activation: activationPayload
41
- });
42
- logger.info(
43
- `[FormEvaluator] Activated external field ${field}: ${activation.instructions}`
44
- );
45
- }
46
- const formIntentProcessor = {
47
- name: "formIntent",
48
- priority: 100,
49
- async process({ output, prepared, runtime: _runtime, message: _message }) {
50
- const { formService, session, form, entityId } = prepared;
51
- switch (output.formIntent) {
52
- case "submit":
53
- await formService.submit(session.id, entityId);
54
- return { success: true, values: { formIntent: "submit" } };
55
- case "stash":
56
- await formService.stash(session.id, entityId);
57
- return { success: true, values: { formIntent: "stash" } };
58
- case "cancel":
59
- await formService.cancel(session.id, entityId);
60
- return { success: true, values: { formIntent: "cancel" } };
61
- case "undo": {
62
- if (!form.ux?.allowUndo) return void 0;
63
- const result = await formService.undoLastChange(session.id, entityId);
64
- return result ? { success: true, values: { formIntent: "undo", undid: result.field } } : void 0;
65
- }
66
- case "skip": {
67
- if (!form.ux?.allowSkip || !session.lastAskedField) return void 0;
68
- const skipped = await formService.skipField(
69
- session.id,
70
- entityId,
71
- session.lastAskedField
72
- );
73
- return skipped ? { success: true, values: { formIntent: "skip", skipped: session.lastAskedField } } : void 0;
74
- }
75
- case "autofill":
76
- await formService.applyAutofill(session);
77
- return { success: true, values: { formIntent: "autofill" } };
78
- case "explain":
79
- case "example":
80
- case "progress":
81
- return { success: true, values: { formIntent: output.formIntent } };
82
- case "restore":
83
- return void 0;
84
- default:
85
- return void 0;
86
- }
87
- }
88
- };
89
- const formExtractionsProcessor = {
90
- name: "formExtractions",
91
- priority: 200,
92
- async process({ output, prepared, runtime, message }) {
93
- const { formService, session, form, entityId } = prepared;
94
- if (output.formIntent !== "fill_form" && output.formIntent !== "other") {
95
- const refreshed2 = await formService.getActiveSession(
96
- entityId,
97
- session.roomId
98
- );
99
- if (refreshed2) {
100
- refreshed2.lastMessageId = message.id;
101
- await formService.saveSession(refreshed2);
102
- }
103
- return void 0;
104
- }
105
- const updatedParents = /* @__PURE__ */ new Set();
106
- const coerced = coerceExtractionsAgainstControls(
107
- output.formExtractions,
108
- form.controls,
109
- prepared.templateValues
110
- );
111
- for (const extraction of coerced) {
112
- if (extraction.field.includes(".")) {
113
- const [parentKey, subKey] = extraction.field.split(".");
114
- await formService.updateSubField(
115
- session.id,
116
- entityId,
117
- parentKey,
118
- subKey,
119
- extraction.value,
120
- extraction.confidence,
121
- message.id
122
- );
123
- await emitEvent(runtime, "FORM_SUBFIELD_UPDATED", {
124
- sessionId: session.id,
125
- parentField: parentKey,
126
- subField: subKey,
127
- value: extraction.value,
128
- confidence: extraction.confidence
129
- });
130
- updatedParents.add(parentKey);
131
- } else {
132
- await formService.updateField(
133
- session.id,
134
- entityId,
135
- extraction.field,
136
- extraction.value,
137
- extraction.confidence,
138
- extraction.isCorrection ? "correction" : "extraction",
139
- message.id
140
- );
141
- await emitEvent(runtime, "FORM_FIELD_EXTRACTED", {
142
- sessionId: session.id,
143
- field: extraction.field,
144
- value: extraction.value,
145
- confidence: extraction.confidence
146
- });
147
- }
148
- }
149
- for (const parentKey of updatedParents) {
150
- await checkAndActivateExternalField(
151
- runtime,
152
- formService,
153
- session,
154
- form,
155
- entityId,
156
- parentKey
157
- );
158
- }
159
- const refreshed = await formService.getActiveSession(
160
- entityId,
161
- session.roomId
162
- );
163
- if (refreshed) {
164
- refreshed.lastMessageId = message.id;
165
- await formService.saveSession(refreshed);
166
- }
167
- return {
168
- success: true,
169
- values: {
170
- extractionCount: output.formExtractions.length
171
- }
172
- };
173
- }
174
- };
175
- const formEvaluator = {
176
- name: "form_extractor",
177
- description: "Extracts form field values and detects form lifecycle/UX intents from the user message",
178
- similes: ["FORM_EXTRACTION", "FORM_HANDLER", "form_evaluator"],
179
- // Run before reflection/memory so downstream evaluators see updated form state.
180
- priority: EvaluatorPriority.FORM,
181
- providers: ["RECENT_MESSAGES"],
182
- schema: buildFormExtractorSchema(),
183
- async shouldRun({ runtime, message }) {
184
- const formService = runtime.getService("FORM");
185
- if (!formService) return false;
186
- const entityId = message.entityId;
187
- const roomId = message.roomId;
188
- if (!entityId || !roomId) return false;
189
- const text = message.content?.text;
190
- if (!text || !text.trim()) return false;
191
- const session = await formService.getActiveSession(entityId, roomId);
192
- if (session) return true;
193
- const stashed = await formService.getStashedSessions(entityId);
194
- return stashed.length > 0;
195
- },
196
- async prepare({ runtime, message }) {
197
- const formService = runtime.getService("FORM");
198
- if (!formService) {
199
- throw new Error("FormService not found in prepare()");
200
- }
201
- const entityId = message.entityId;
202
- const roomId = message.roomId;
203
- const session = await formService.getActiveSession(entityId, roomId);
204
- if (!session) {
205
- throw new Error(
206
- "Form evaluator prepared without an active session; FORM_RESTORE owns the stashed-only path"
207
- );
208
- }
209
- const form = formService.getForm(session.formId);
210
- if (!form) {
211
- throw new Error(
212
- `Form definition not found for session formId=${session.formId}`
213
- );
214
- }
215
- return {
216
- formService,
217
- session,
218
- form,
219
- templateValues: buildTemplateValues(session),
220
- entityId
221
- };
222
- },
223
- prompt({ message, prepared }) {
224
- const text = message.content?.text ?? "";
225
- return buildFormExtractorPromptSection({
226
- text,
227
- form: prepared.form,
228
- controls: prepared.form.controls,
229
- templateValues: prepared.templateValues
230
- });
231
- },
232
- parse(raw) {
233
- const parsed = parseFormExtractorOutput(raw);
234
- if (!parsed) return null;
235
- return {
236
- formIntent: parsed.intent,
237
- formExtractions: parsed.extractions
238
- };
239
- },
240
- processors: [formIntentProcessor, formExtractionsProcessor]
241
- };
242
- var extractor_default = formEvaluator;
243
- export {
244
- extractor_default as default,
245
- formEvaluator
246
- };
247
- //# sourceMappingURL=extractor.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/evaluators/extractor.ts"],"sourcesContent":["/**\n * @module evaluators/extractor\n * @description Form post-turn evaluator that runs in the unified\n * EvaluatorService pass. Detects form intents (submit, stash, cancel, undo,\n * skip, autofill, info) and extracts field values from the user message,\n * then mutates session state accordingly.\n *\n * The 'restore' intent is handled by FORM_RESTORE (a planner Action) so the\n * restored form is in scope before the agent's response is generated.\n */\n\nimport type {\n EventPayload,\n Evaluator,\n EvaluatorProcessor,\n IAgentRuntime,\n JsonValue,\n UUID,\n} from \"@elizaos/core\";\nimport { EvaluatorPriority, logger } from \"@elizaos/core\";\nimport {\n buildFormExtractorPromptSection,\n buildFormExtractorSchema,\n coerceExtractionsAgainstControls,\n parseFormExtractorOutput,\n} from \"../extraction\";\nimport type { FormService } from \"../service\";\nimport { buildTemplateValues, type TemplateValues } from \"../template\";\nimport type {\n ExtractionResult,\n FormDefinition,\n FormIntent,\n FormSession,\n} from \"../types\";\n\ninterface FormExtractorOutput {\n formIntent: FormIntent;\n formExtractions: ExtractionResult[];\n}\n\ninterface FormExtractorPrepared {\n formService: FormService;\n session: FormSession;\n form: FormDefinition;\n templateValues: TemplateValues;\n entityId: UUID;\n}\n\nasync function emitEvent(\n runtime: IAgentRuntime,\n eventType: string,\n payload: Record<string, JsonValue>,\n): Promise<void> {\n if (typeof runtime.emitEvent !== \"function\") return;\n const eventPayload: EventPayload = { runtime, ...payload };\n await runtime.emitEvent(eventType, eventPayload);\n}\n\nasync function checkAndActivateExternalField(\n runtime: IAgentRuntime,\n formService: FormService,\n session: FormSession,\n form: FormDefinition,\n entityId: UUID,\n field: string,\n): Promise<void> {\n const freshSession = await formService.getActiveSession(\n entityId,\n session.roomId,\n );\n if (!freshSession) return;\n\n const control = form.controls.find((c) => c.key === field);\n if (!control || !formService.isExternalType(control.type)) return;\n if (!formService.areSubFieldsFilled(freshSession, field)) return;\n\n const subValues = formService.getSubFieldValues(freshSession, field);\n await emitEvent(runtime, \"FORM_SUBCONTROLS_FILLED\", {\n sessionId: session.id,\n field,\n subValues,\n });\n\n const activation = await formService.activateExternalField(\n session.id,\n entityId,\n field,\n );\n const activationPayload = JSON.parse(\n JSON.stringify(activation),\n ) as JsonValue;\n\n await emitEvent(runtime, \"FORM_EXTERNAL_ACTIVATED\", {\n sessionId: session.id,\n field,\n activation: activationPayload,\n });\n\n logger.info(\n `[FormEvaluator] Activated external field ${field}: ${activation.instructions}`,\n );\n}\n\nconst formIntentProcessor: EvaluatorProcessor<\n FormExtractorOutput,\n FormExtractorPrepared\n> = {\n name: \"formIntent\",\n priority: 100,\n async process({ output, prepared, runtime: _runtime, message: _message }) {\n const { formService, session, form, entityId } = prepared;\n\n switch (output.formIntent) {\n case \"submit\":\n await formService.submit(session.id, entityId);\n return { success: true, values: { formIntent: \"submit\" } };\n\n case \"stash\":\n await formService.stash(session.id, entityId);\n return { success: true, values: { formIntent: \"stash\" } };\n\n case \"cancel\":\n await formService.cancel(session.id, entityId);\n return { success: true, values: { formIntent: \"cancel\" } };\n\n case \"undo\": {\n if (!form.ux?.allowUndo) return undefined;\n const result = await formService.undoLastChange(session.id, entityId);\n return result\n ? { success: true, values: { formIntent: \"undo\", undid: result.field } }\n : undefined;\n }\n\n case \"skip\": {\n if (!form.ux?.allowSkip || !session.lastAskedField) return undefined;\n const skipped = await formService.skipField(\n session.id,\n entityId,\n session.lastAskedField,\n );\n return skipped\n ? { success: true, values: { formIntent: \"skip\", skipped: session.lastAskedField } }\n : undefined;\n }\n\n case \"autofill\":\n await formService.applyAutofill(session);\n return { success: true, values: { formIntent: \"autofill\" } };\n\n case \"explain\":\n case \"example\":\n case \"progress\":\n return { success: true, values: { formIntent: output.formIntent } };\n\n case \"restore\":\n // FORM_RESTORE action owns this path; nothing to do here.\n return undefined;\n\n default:\n return undefined;\n }\n },\n};\n\nconst formExtractionsProcessor: EvaluatorProcessor<\n FormExtractorOutput,\n FormExtractorPrepared\n> = {\n name: \"formExtractions\",\n priority: 200,\n async process({ output, prepared, runtime, message }) {\n const { formService, session, form, entityId } = prepared;\n\n // Lifecycle / UX intents shouldn't double-process extractions; only\n // fill_form and `other` may carry inline data.\n if (\n output.formIntent !== \"fill_form\" &&\n output.formIntent !== \"other\"\n ) {\n // Still update last-message tracking before bailing so deduplication works.\n const refreshed = await formService.getActiveSession(\n entityId,\n session.roomId,\n );\n if (refreshed) {\n refreshed.lastMessageId = message.id;\n await formService.saveSession(refreshed);\n }\n return undefined;\n }\n\n const updatedParents = new Set<string>();\n const coerced = coerceExtractionsAgainstControls(\n output.formExtractions,\n form.controls,\n prepared.templateValues,\n );\n\n for (const extraction of coerced) {\n if (extraction.field.includes(\".\")) {\n const [parentKey, subKey] = extraction.field.split(\".\");\n await formService.updateSubField(\n session.id,\n entityId,\n parentKey,\n subKey,\n extraction.value,\n extraction.confidence,\n message.id,\n );\n await emitEvent(runtime, \"FORM_SUBFIELD_UPDATED\", {\n sessionId: session.id,\n parentField: parentKey,\n subField: subKey,\n value: extraction.value,\n confidence: extraction.confidence,\n });\n updatedParents.add(parentKey);\n } else {\n await formService.updateField(\n session.id,\n entityId,\n extraction.field,\n extraction.value,\n extraction.confidence,\n extraction.isCorrection ? \"correction\" : \"extraction\",\n message.id,\n );\n await emitEvent(runtime, \"FORM_FIELD_EXTRACTED\", {\n sessionId: session.id,\n field: extraction.field,\n value: extraction.value,\n confidence: extraction.confidence,\n });\n }\n }\n\n for (const parentKey of updatedParents) {\n await checkAndActivateExternalField(\n runtime,\n formService,\n session,\n form,\n entityId,\n parentKey,\n );\n }\n\n const refreshed = await formService.getActiveSession(\n entityId,\n session.roomId,\n );\n if (refreshed) {\n refreshed.lastMessageId = message.id;\n await formService.saveSession(refreshed);\n }\n\n return {\n success: true,\n values: {\n extractionCount: output.formExtractions.length,\n },\n };\n },\n};\n\nexport const formEvaluator: Evaluator<\n FormExtractorOutput,\n FormExtractorPrepared\n> = {\n name: \"form_extractor\",\n description:\n \"Extracts form field values and detects form lifecycle/UX intents from the user message\",\n similes: [\"FORM_EXTRACTION\", \"FORM_HANDLER\", \"form_evaluator\"],\n // Run before reflection/memory so downstream evaluators see updated form state.\n priority: EvaluatorPriority.FORM,\n providers: [\"RECENT_MESSAGES\"],\n schema: buildFormExtractorSchema(),\n\n async shouldRun({ runtime, message }) {\n const formService = runtime.getService(\"FORM\") as FormService | null;\n if (!formService) return false;\n\n const entityId = message.entityId as UUID | undefined;\n const roomId = message.roomId as UUID | undefined;\n if (!entityId || !roomId) return false;\n\n const text = message.content?.text;\n if (!text || !text.trim()) return false;\n\n const session = await formService.getActiveSession(entityId, roomId);\n if (session) return true;\n\n const stashed = await formService.getStashedSessions(entityId);\n return stashed.length > 0;\n },\n\n async prepare({ runtime, message }) {\n const formService = runtime.getService(\"FORM\") as FormService | null;\n if (!formService) {\n throw new Error(\"FormService not found in prepare()\");\n }\n const entityId = message.entityId as UUID;\n const roomId = message.roomId as UUID;\n\n const session = await formService.getActiveSession(entityId, roomId);\n if (!session) {\n // shouldRun gates this — only stashed-only state reaches here, in which\n // case the evaluator section will produce an `other` intent and no\n // extractions will be applied because there's no active session.\n throw new Error(\n \"Form evaluator prepared without an active session; FORM_RESTORE owns the stashed-only path\",\n );\n }\n\n const form = formService.getForm(session.formId);\n if (!form) {\n throw new Error(\n `Form definition not found for session formId=${session.formId}`,\n );\n }\n\n return {\n formService,\n session,\n form,\n templateValues: buildTemplateValues(session),\n entityId,\n };\n },\n\n prompt({ message, prepared }) {\n const text = message.content?.text ?? \"\";\n return buildFormExtractorPromptSection({\n text,\n form: prepared.form,\n controls: prepared.form.controls,\n templateValues: prepared.templateValues,\n });\n },\n\n parse(raw) {\n const parsed = parseFormExtractorOutput(raw);\n if (!parsed) return null;\n return {\n formIntent: parsed.intent,\n formExtractions: parsed.extractions,\n };\n },\n\n processors: [formIntentProcessor, formExtractionsProcessor],\n};\n\nexport default formEvaluator;\n"],"mappings":"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","names":["refreshed"]}
@@ -1,55 +0,0 @@
1
- /**
2
- * @module extraction
3
- * @description LLM-based field extraction from natural language.
4
- *
5
- * Exposes prompt/schema/parse helpers consumed by the form Evaluator and
6
- * runs the LLM call directly only for the targeted single-field and
7
- * correction-detection helpers.
8
- */
9
- import type { IAgentRuntime, JSONSchema, JsonValue } from "@elizaos/core";
10
- import type { TemplateValues } from "./template";
11
- import type { ExtractionResult, FormControl, FormDefinition, IntentResult } from "./types";
12
- /**
13
- * Build the JSON Schema fragment for the form-extractor evaluator section.
14
- *
15
- * Returned shape:
16
- * { formIntent: <enum>, formExtractions: [{ field, value, confidence, isCorrection }] }
17
- */
18
- export declare function buildFormExtractorSchema(): JSONSchema;
19
- /**
20
- * Build the prompt section for the form-extractor evaluator.
21
- *
22
- * The unified evaluator prompt inlines this string and asks the model to
23
- * populate `{ formIntent, formExtractions }` for the active form.
24
- */
25
- export declare function buildFormExtractorPromptSection(params: {
26
- text: string;
27
- form: FormDefinition;
28
- controls: FormControl[];
29
- templateValues?: TemplateValues;
30
- }): string;
31
- /**
32
- * Parse the raw `{ formIntent, formExtractions }` object produced by the
33
- * unified evaluator pass into a typed `IntentResult`. Type coercion and
34
- * validation against control rules happen later (in the processor) where
35
- * the form definition is in scope.
36
- */
37
- export declare function parseFormExtractorOutput(raw: unknown): IntentResult | null;
38
- /**
39
- * Apply type coercion + validation to a parsed extractions list against the
40
- * resolved form controls. Lowers confidence to 0.3 when a value fails the
41
- * control's validator (so downstream confirmation flow kicks in).
42
- */
43
- export declare function coerceExtractionsAgainstControls(extractions: ExtractionResult[], controls: FormControl[], templateValues?: TemplateValues): ExtractionResult[];
44
- /**
45
- * Extract a specific field value from a user message with a focused prompt.
46
- *
47
- * Used when the agent has just asked for a specific field and expects a
48
- * direct answer. Independent of the unified evaluator pass.
49
- */
50
- export declare function extractSingleField(runtime: IAgentRuntime, text: string, control: FormControl, debug?: boolean, templateValues?: TemplateValues): Promise<ExtractionResult | null>;
51
- /**
52
- * Detect whether the user is correcting a previously filled value.
53
- */
54
- export declare function detectCorrection(runtime: IAgentRuntime, text: string, currentValues: Record<string, JsonValue>, controls: FormControl[], templateValues?: TemplateValues): Promise<ExtractionResult[]>;
55
- //# sourceMappingURL=extraction.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"extraction.d.ts","sourceRoot":"","sources":["../src/extraction.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,OAAO,KAAK,EACV,gBAAgB,EAChB,WAAW,EACX,cAAc,EAEd,YAAY,EACb,MAAM,SAAS,CAAC;AA0FjB;;;;;GAKG;AACH,wBAAgB,wBAAwB,IAAI,UAAU,CA2BrD;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAAC,MAAM,EAAE;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,cAAc,CAAC;IACrB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC,GAAG,MAAM,CAsDT;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI,CA+C1E;AAED;;;;GAIG;AACH,wBAAgB,gCAAgC,CAC9C,WAAW,EAAE,gBAAgB,EAAE,EAC/B,QAAQ,EAAE,WAAW,EAAE,EACvB,cAAc,CAAC,EAAE,cAAc,GAC9B,gBAAgB,EAAE,CA+BpB;AAMD;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,aAAa,EACtB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,WAAW,EACpB,KAAK,CAAC,EAAE,OAAO,EACf,cAAc,CAAC,EAAE,cAAc,GAC9B,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAsElC;AAMD;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,aAAa,EACtB,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,EACxC,QAAQ,EAAE,WAAW,EAAE,EACvB,cAAc,CAAC,EAAE,cAAc,GAC9B,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAiG7B"}
@@ -1,331 +0,0 @@
1
- import { ModelType } from "@elizaos/core";
2
- import { resolveControlTemplates } from "./template";
3
- import { getTypeHandler, parseValue, validateField } from "./validation";
4
- const FORM_INTENTS = [
5
- "fill_form",
6
- "submit",
7
- "stash",
8
- "restore",
9
- "cancel",
10
- "undo",
11
- "skip",
12
- "explain",
13
- "example",
14
- "progress",
15
- "autofill",
16
- "other"
17
- ];
18
- const INTENT_MEANINGS = {
19
- fill_form: "user is providing field values",
20
- submit: "user wants to submit or finish the form",
21
- stash: "user wants to save or pause the form for later",
22
- restore: "user wants to resume a saved form",
23
- cancel: "user wants to cancel or abandon the form",
24
- undo: "user wants to undo the last change",
25
- skip: "user wants to skip the current field",
26
- explain: "user wants an explanation",
27
- example: "user wants an example value",
28
- progress: "user wants a progress update",
29
- autofill: "user wants to use saved values",
30
- other: "none of the above"
31
- };
32
- function parseJsonObjectResponse(response) {
33
- try {
34
- const trimmed = response.trim();
35
- const fenced = trimmed.match(/```(?:json)?\s*([\s\S]*?)\s*```/i);
36
- const candidate = (fenced?.[1] ?? trimmed).trim();
37
- const firstBrace = candidate.indexOf("{");
38
- const lastBrace = candidate.lastIndexOf("}");
39
- if (firstBrace < 0 || lastBrace <= firstBrace) return null;
40
- const parsed = JSON.parse(candidate.slice(firstBrace, lastBrace + 1));
41
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
42
- return null;
43
- }
44
- return parsed;
45
- } catch {
46
- return null;
47
- }
48
- }
49
- function parseBoolean(value) {
50
- return String(value ?? "").trim().toLowerCase() === "true";
51
- }
52
- function isRecord(value) {
53
- return typeof value === "object" && value !== null && !Array.isArray(value);
54
- }
55
- function isValidIntent(str) {
56
- return FORM_INTENTS.includes(str);
57
- }
58
- function buildFormExtractorSchema() {
59
- return {
60
- type: "object",
61
- properties: {
62
- formIntent: {
63
- type: "string",
64
- enum: [...FORM_INTENTS]
65
- },
66
- formExtractions: {
67
- type: "array",
68
- items: {
69
- type: "object",
70
- properties: {
71
- field: { type: "string" },
72
- value: {},
73
- confidence: { type: "number" },
74
- isCorrection: { type: "boolean" },
75
- reasoning: { type: "string" }
76
- },
77
- required: ["field", "confidence"],
78
- additionalProperties: false
79
- }
80
- }
81
- },
82
- required: ["formIntent", "formExtractions"],
83
- additionalProperties: false
84
- };
85
- }
86
- function buildFormExtractorPromptSection(params) {
87
- const { text, form, controls, templateValues } = params;
88
- const resolvedControls = templateValues ? controls.map(
89
- (control) => resolveControlTemplates(control, templateValues)
90
- ) : controls;
91
- const visibleControls = resolvedControls.filter((c) => !c.hidden);
92
- const fieldsDescription = visibleControls.map((c) => {
93
- const handler = getTypeHandler(c.type);
94
- const typeHint = handler?.extractionPrompt || c.type;
95
- return {
96
- key: c.key,
97
- label: c.label,
98
- type: typeHint,
99
- description: c.description || typeHint,
100
- hints: c.extractHints ?? [],
101
- options: c.options?.map((o) => o.value) ?? []
102
- };
103
- });
104
- return `Extract form intent and field values for the active form session.
105
-
106
- Context JSON:
107
- ${JSON.stringify(
108
- {
109
- form: {
110
- name: form.name,
111
- description: form.description
112
- },
113
- fields: fieldsDescription,
114
- user_message: text,
115
- intent_options: FORM_INTENTS,
116
- intent_meanings: INTENT_MEANINGS
117
- },
118
- null,
119
- 2
120
- )}
121
-
122
- Populate this evaluator's section as:
123
- {
124
- "formIntent": "one of intent_options",
125
- "formExtractions": [
126
- { "field": "<key>", "value": <extracted>, "confidence": 0.0-1.0, "isCorrection": false, "reasoning": "brief" }
127
- ]
128
- }
129
-
130
- Rules:
131
- - Choose exactly one intent.
132
- - For fill_form, extract every mentioned field value.
133
- - Use an empty formExtractions array when no fields were extracted.
134
- - Confidence is a number from 0.0 to 1.0.`;
135
- }
136
- function parseFormExtractorOutput(raw) {
137
- if (!isRecord(raw)) return null;
138
- const intentStr = typeof raw.formIntent === "string" ? raw.formIntent.toLowerCase() : "other";
139
- const intent = isValidIntent(intentStr) ? intentStr : "other";
140
- const rawExtractions = Array.isArray(raw.formExtractions) ? raw.formExtractions : [];
141
- const extractions = [];
142
- const seen = /* @__PURE__ */ new Set();
143
- for (const entry of rawExtractions) {
144
- if (!isRecord(entry)) continue;
145
- const fieldKey = typeof entry.field === "string" ? entry.field : "";
146
- if (!fieldKey) continue;
147
- const dedupeKey = `${fieldKey}\0${String(entry.value ?? "")}`;
148
- if (seen.has(dedupeKey)) continue;
149
- seen.add(dedupeKey);
150
- const value = entry.value ?? null;
151
- let confidence = typeof entry.confidence === "number" ? entry.confidence : parseFloat(String(entry.confidence ?? ""));
152
- if (!Number.isFinite(confidence)) confidence = 0.5;
153
- const reasoning = typeof entry.reasoning === "string" ? entry.reasoning : void 0;
154
- extractions.push({
155
- field: fieldKey,
156
- value,
157
- confidence,
158
- reasoning,
159
- isCorrection: parseBoolean(entry.isCorrection)
160
- });
161
- }
162
- return { intent, extractions };
163
- }
164
- function coerceExtractionsAgainstControls(extractions, controls, templateValues) {
165
- const resolvedControls = templateValues ? controls.map(
166
- (control) => resolveControlTemplates(control, templateValues)
167
- ) : controls;
168
- return extractions.map((extraction) => {
169
- if (extraction.field.includes(".")) return extraction;
170
- const control = resolvedControls.find((c) => c.key === extraction.field);
171
- if (!control) return extraction;
172
- let value = extraction.value;
173
- if (typeof value === "string") {
174
- value = parseValue(value, control);
175
- }
176
- const validation = validateField(value, control);
177
- if (!validation.valid) {
178
- const reasoning = `${extraction.reasoning ?? ""} (Validation failed: ${validation.error})`.trim();
179
- return {
180
- ...extraction,
181
- value,
182
- confidence: Math.min(extraction.confidence, 0.3),
183
- reasoning
184
- };
185
- }
186
- return { ...extraction, value };
187
- });
188
- }
189
- async function extractSingleField(runtime, text, control, debug, templateValues) {
190
- const resolvedControl = templateValues ? resolveControlTemplates(control, templateValues) : control;
191
- const handler = getTypeHandler(resolvedControl.type);
192
- const typeHint = handler?.extractionPrompt || resolvedControl.type;
193
- const prompt = `Extract a single form field value from the user message.
194
-
195
- Context JSON:
196
- ${JSON.stringify(
197
- {
198
- field: {
199
- key: resolvedControl.key,
200
- label: resolvedControl.label,
201
- type: typeHint,
202
- description: resolvedControl.description,
203
- hints: resolvedControl.extractHints ?? [],
204
- options: resolvedControl.options?.map((o) => o.value) ?? [],
205
- example: resolvedControl.example
206
- },
207
- user_message: text
208
- },
209
- null,
210
- 2
211
- )}
212
-
213
- Return only a valid JSON object with this schema:
214
- {
215
- "found": true,
216
- "value": "extracted value or null if not found",
217
- "confidence": 0.95,
218
- "reasoning": "brief explanation"
219
- }`;
220
- const runModel = runtime.useModel.bind(runtime);
221
- const response = await runModel(ModelType.TEXT_SMALL, {
222
- prompt,
223
- temperature: 0.1
224
- });
225
- const parsed = parseJsonObjectResponse(response);
226
- const found = parsed?.found === true || parsed?.found === "true";
227
- if (!found || !parsed) return null;
228
- let value = parsed.value;
229
- if (typeof value === "string") {
230
- value = parseValue(value, resolvedControl);
231
- }
232
- const confidence = typeof parsed.confidence === "number" ? parsed.confidence : parseFloat(String(parsed.confidence ?? ""));
233
- const result = {
234
- field: resolvedControl.key,
235
- value: value ?? null,
236
- confidence: Number.isFinite(confidence) ? confidence : 0.5,
237
- reasoning: parsed.reasoning ? String(parsed.reasoning) : void 0
238
- };
239
- if (debug) {
240
- runtime.logger.debug(
241
- "[FormExtraction] Single field extraction:",
242
- JSON.stringify(result)
243
- );
244
- }
245
- return result;
246
- }
247
- async function detectCorrection(runtime, text, currentValues, controls, templateValues) {
248
- const resolvedControls = templateValues ? controls.map(
249
- (control) => resolveControlTemplates(control, templateValues)
250
- ) : controls;
251
- const currentValueEntries = resolvedControls.filter(
252
- (c) => currentValues[c.key] !== void 0
253
- );
254
- if (currentValueEntries.length === 0) return [];
255
- const currentValueRows = currentValueEntries.map((c) => ({
256
- key: c.key,
257
- label: c.label,
258
- value: currentValues[c.key]
259
- }));
260
- const prompt = `Detect whether the user is correcting a previous form value.
261
-
262
- Context JSON:
263
- ${JSON.stringify(
264
- {
265
- current_values: currentValueRows,
266
- user_message: text
267
- },
268
- null,
269
- 2
270
- )}
271
-
272
- Return only a valid JSON object with this schema:
273
- {
274
- "has_correction": true,
275
- "corrections": [
276
- {
277
- "field": "email",
278
- "old_value": "old@example.com",
279
- "new_value": "new@example.com",
280
- "confidence": 0.9
281
- }
282
- ]
283
- }
284
-
285
- Rules:
286
- - Decide whether the user is correcting a previous value.
287
- - When correcting, extract the replacement value.
288
- - Use an empty corrections array when no corrections were found.`;
289
- const runModel = runtime.useModel.bind(runtime);
290
- const response = await runModel(ModelType.TEXT_SMALL, {
291
- prompt,
292
- temperature: 0.1
293
- });
294
- const parsed = parseJsonObjectResponse(response);
295
- const hasCorrection = parsed?.has_correction === true || parsed?.has_correction === "true";
296
- if (!parsed || !hasCorrection || !parsed.corrections) return [];
297
- const corrections = [];
298
- const correctionList = Array.isArray(parsed.corrections) ? parsed.corrections : [];
299
- const seen = /* @__PURE__ */ new Set();
300
- for (const correction of correctionList) {
301
- const fieldName = correction.field ? String(correction.field) : "";
302
- const control = resolvedControls.find(
303
- (c) => c.label.toLowerCase() === fieldName.toLowerCase() || c.key.toLowerCase() === fieldName.toLowerCase()
304
- );
305
- if (!control) continue;
306
- const dedupeKey = `${control.key}\0${String(correction.new_value ?? "")}`;
307
- if (seen.has(dedupeKey)) continue;
308
- seen.add(dedupeKey);
309
- let value = correction.new_value;
310
- if (typeof value === "string") {
311
- value = parseValue(value, control);
312
- }
313
- const confidence = typeof correction.confidence === "number" ? correction.confidence : parseFloat(String(correction.confidence ?? ""));
314
- corrections.push({
315
- field: control.key,
316
- value: value ?? null,
317
- confidence: Number.isFinite(confidence) ? confidence : 0.8,
318
- isCorrection: true
319
- });
320
- }
321
- return corrections;
322
- }
323
- export {
324
- buildFormExtractorPromptSection,
325
- buildFormExtractorSchema,
326
- coerceExtractionsAgainstControls,
327
- detectCorrection,
328
- extractSingleField,
329
- parseFormExtractorOutput
330
- };
331
- //# sourceMappingURL=extraction.js.map