Skip to content

Commit af09c4a

Browse files
committed
2 parents 1bb1349 + 0f23d82 commit af09c4a

File tree

6 files changed

+119
-7
lines changed

6 files changed

+119
-7
lines changed

docs/API_REFERENCE.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,10 @@ Override the order in which providers are tried. Inherits from `AIFormProvider`
423423

424424
Automatically try the next provider if one fails. Default: `true`
425425

426+
#### `formContext?: string | Record<string, any>`
427+
428+
Context information for AI to use when generating suggestions. Can be a string description or an object with contextual data.
429+
426430
**Example:**
427431

428432
```tsx
@@ -436,7 +440,8 @@ const form = useForm<FormData>({
436440
{ type: 'openai', apiKey: 'sk-...', priority: 5 }
437441
],
438442
executionOrder: ['chrome', 'openai'],
439-
fallbackOnError: true
443+
fallbackOnError: true,
444+
formContext: 'Senior software engineer applying for a tech lead position'
440445
}
441446
});
442447
```
@@ -477,6 +482,10 @@ Debounce time in milliseconds for AI suggestions. Default: `800`
477482

478483
Array of field names to exclude from AI processing. Default: `[]`
479484

485+
#### `formContext?: string | Record<string, any>`
486+
487+
Global context information for AI to use when generating suggestions. Can be a string description or an object with contextual data. Forms can override this with their own local context.
488+
480489
---
481490

482491
## Types
@@ -634,6 +643,10 @@ Set to `false` to disable this provider. Optional.
634643

635644
Higher values are tried first. Optional, default: 0.
636645

646+
#### `systemPrompt?: string`
647+
648+
Custom prompt template for Chrome AI. Use placeholders `{fieldName}`, `{currentValue}`, `{formContext}`, and `{fields}` for dynamic values. If not provided, uses the default prompt.
649+
637650
**Features:**
638651
-No API key required
639652
-Browser-based and privacy-friendly
@@ -646,7 +659,8 @@ Higher values are tried first. Optional, default: 0.
646659
```tsx
647660
const config: ChromeAIConfig = {
648661
type: 'chrome',
649-
priority: 10
662+
priority: 10,
663+
systemPrompt: 'You are a professional recruiter. For field {fieldName} with value "{currentValue}", suggest a professional response. Context: {formContext}. Return only the value.'
650664
};
651665
```
652666

docs/PROVIDERS.md

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ Chrome's experimental on-device AI. Privacy-friendly and free, but requires Chro
1515
```tsx
1616
{
1717
type: 'chrome',
18-
priority: 10 // Optional: higher priority = tried first
18+
priority: 10, // Optional: higher priority = tried first
19+
systemPrompt: 'Custom prompt...' // Optional: custom AI prompt template
1920
}
2021
```
2122

@@ -34,6 +35,29 @@ Chrome's experimental on-device AI. Privacy-friendly and free, but requires Chro
3435
3. Set to "Enabled"
3536
4. Restart Chrome
3637

38+
### Custom Prompts
39+
40+
Customize how Chrome AI generates suggestions using the `systemPrompt` option:
41+
42+
```tsx
43+
{
44+
type: 'chrome',
45+
priority: 10,
46+
systemPrompt: `You are a professional form assistant.
47+
For the field named {fieldName} with current value "{currentValue}",
48+
provide a suggestion based on this context: {formContext}.
49+
Return only the suggested value, no explanations.`
50+
}
51+
```
52+
53+
**Available placeholders:**
54+
- `{fieldName}` - The name of the field being filled
55+
- `{currentValue}` - The current value in the field
56+
- `{formContext}` - The form context as JSON
57+
- `{fields}` - List of all form fields (for autofill)
58+
59+
If no custom prompt is provided, a sensible default is used.
60+
3761
### Handling Model Download
3862

3963
The AI model (~1-2GB) downloads on first use. Handle this gracefully:
@@ -225,6 +249,44 @@ Connect to browser-based AI services.
225249
}
226250
```
227251

252+
## Form Context
253+
254+
Provide contextual information to help AI generate better suggestions:
255+
256+
```tsx
257+
<AIFormProvider
258+
providers={[{ type: 'chrome', priority: 10 }]}
259+
formContext="Senior software engineer with 8+ years of experience applying for a tech lead position"
260+
>
261+
<App />
262+
</AIFormProvider>
263+
```
264+
265+
Or use an object for structured context:
266+
267+
```tsx
268+
<AIFormProvider
269+
providers={[{ type: 'chrome', priority: 10 }]}
270+
formContext={{
271+
role: 'Senior Engineer',
272+
experience: '8+ years',
273+
specialization: 'Full-stack development'
274+
}}
275+
>
276+
<App />
277+
</AIFormProvider>
278+
```
279+
280+
Forms can override the global context:
281+
282+
```tsx
283+
const form = useForm({
284+
ai: {
285+
formContext: 'Junior developer with 2 years of experience'
286+
}
287+
});
288+
```
289+
228290
## Multi-Provider Setup
229291

230292
Configure multiple providers with automatic fallback:
@@ -255,6 +317,7 @@ Configure multiple providers with automatic fallback:
255317
]}
256318
executionOrder={['chrome', 'openai', 'custom']}
257319
fallbackOnError={true}
320+
formContext="Default context for all forms"
258321
>
259322
<App />
260323
</AIFormProvider>

src/AIFormProvider.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ export interface AIFormProviderProps {
1919
enabled?: boolean;
2020
debounceMs?: number;
2121
excludeFields?: string[];
22+
/** Global context for AI to use when filling forms (optional) */
23+
formContext?: string | Record<string, any>;
2224
}
2325

2426
/**

src/aiProviders.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ interface AIProviderExecutor {
5555
* Chrome Built-in AI Provider
5656
*/
5757
class ChromeAIProvider implements AIProviderExecutor {
58+
constructor(private config?: Extract<AIProvider, { type: 'chrome' }>) {}
59+
5860
async checkAvailability() {
5961
if (typeof window === 'undefined' || typeof LanguageModel === 'undefined') {
6062
return { available: false, status: 'unavailable', needsDownload: false };
@@ -78,7 +80,7 @@ class ChromeAIProvider implements AIProviderExecutor {
7880
formContext: Record<string, any>
7981
): Promise<AIResponse | null> {
8082
try {
81-
const prompt = `You are assisting with form completion. The user is filling out a field named "${fieldName}".
83+
const defaultPrompt = `You are assisting with form completion. The user is filling out a field named "${fieldName}".
8284
8385
Current value: "${currentValue}"
8486
Form context: ${JSON.stringify(formContext, null, 2)}
@@ -93,6 +95,13 @@ Rules:
9395
9496
Suggested value:`;
9597

98+
const prompt = this.config?.systemPrompt
99+
? this.config.systemPrompt
100+
.replace('{fieldName}', fieldName)
101+
.replace('{currentValue}', currentValue)
102+
.replace('{formContext}', JSON.stringify(formContext, null, 2))
103+
: defaultPrompt;
104+
96105
const session = await LanguageModel.create();
97106
const result = await session.prompt(prompt);
98107
session.destroy();
@@ -111,7 +120,7 @@ Suggested value:`;
111120
onProgress?: (progress: number) => void
112121
): Promise<AutofillData | null> {
113122
try {
114-
const prompt = `You are an intelligent form assistant. Generate realistic example values for a form.
123+
const defaultPrompt = `You are an intelligent form assistant. Generate realistic example values for a form.
115124
116125
Form fields: ${fields.join(', ')}
117126
Context: ${JSON.stringify(formContext, null, 2)}
@@ -124,6 +133,12 @@ Example format:
124133
125134
JSON object:`;
126135

136+
const prompt = this.config?.systemPrompt
137+
? this.config.systemPrompt
138+
.replace('{fields}', fields.join(', '))
139+
.replace('{formContext}', JSON.stringify(formContext, null, 2))
140+
: defaultPrompt;
141+
127142
const session = await LanguageModel.create({
128143
monitor(m) {
129144
m.addEventListener('downloadprogress', (e) => {
@@ -338,7 +353,7 @@ class CustomServerProvider implements AIProviderExecutor {
338353
export function createAIProvider(config: AIProvider): AIProviderExecutor {
339354
switch (config.type) {
340355
case 'chrome':
341-
return new ChromeAIProvider();
356+
return new ChromeAIProvider(config);
342357
case 'openai':
343358
return new OpenAIProvider(config);
344359
case 'custom':

src/types/ai.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ export interface CustomServerConfig extends AIProviderConfig {
107107
export interface ChromeAIConfig extends AIProviderConfig {
108108
/** Must be 'chrome' */
109109
type: 'chrome';
110+
systemPrompt?: string;
110111
}
111112

112113
/**
@@ -188,6 +189,8 @@ export interface AIFormContextValue {
188189
debounceMs: number;
189190
/** Array of field names to exclude from AI processing */
190191
excludeFields: string[];
192+
/** Global context for AI to use when filling forms (optional) */
193+
formContext?: string | Record<string, any>;
191194
}
192195

193196
/**

src/useForm.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ export interface AIFormOptions {
5151
executionOrder?: AIProviderType[];
5252
/** Override fallback behavior from AIFormProvider */
5353
fallbackOnError?: boolean;
54+
/** Context for AI to use when filling forms (optional) */
55+
formContext?: string | Record<string, any>;
5456
}
5557

5658
/**
@@ -169,6 +171,7 @@ export function useForm<T extends FieldValues>(
169171
providers: localProviders,
170172
executionOrder: localOrder,
171173
fallbackOnError: localFallback,
174+
formContext: localFormContext,
172175
} = aiOptions || {};
173176

174177
return {
@@ -180,6 +183,7 @@ export function useForm<T extends FieldValues>(
180183
providers: localProviders ?? providerContext?.providers,
181184
executionOrder: localOrder ?? providerContext?.executionOrder,
182185
fallbackOnError: localFallback ?? providerContext?.fallbackOnError ?? true,
186+
formContext: localFormContext ?? providerContext?.formContext,
183187
};
184188
}, [aiOptions, providerContext]);
185189

@@ -192,6 +196,7 @@ export function useForm<T extends FieldValues>(
192196
providers,
193197
executionOrder,
194198
fallbackOnError,
199+
formContext: configFormContext,
195200
} = mergedConfig;
196201

197202
const form = useReactHookForm<T>(rhfOptions);
@@ -209,10 +214,20 @@ export function useForm<T extends FieldValues>(
209214
// Get current form values for context
210215
const formValues = form.watch();
211216

217+
// Merge form values with configured context
218+
const mergedFormContext = useMemo(() => {
219+
if (typeof configFormContext === 'string') {
220+
return { ...formValues, _context: configFormContext };
221+
} else if (configFormContext) {
222+
return { ...formValues, ...configFormContext };
223+
}
224+
return formValues;
225+
}, [formValues, configFormContext]);
226+
212227
// Initialize AI assistant with form context and overrides
213228
const ai = useAIAssistant({
214229
enabled: aiEnabled,
215-
formContext: formValues,
230+
formContext: mergedFormContext,
216231
apiUrl,
217232
providers,
218233
executionOrder,

0 commit comments

Comments
 (0)