orchid-ai 1.2.8 → 1.3.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.
@@ -24,6 +24,7 @@ export declare class ContextualCommandService {
24
24
  private buildContextualSystemPrompt;
25
25
  /**
26
26
  * Format schema fields into readable descriptions
27
+ * Excludes client-generated fields from the output
27
28
  */
28
29
  private formatSchemaFields;
29
30
  /**
@@ -483,6 +483,8 @@ export interface SchemaProperty {
483
483
  maxLength?: number;
484
484
  minimum?: number;
485
485
  maximum?: number;
486
+ /** If true, this field is not to be generated by AI (e.g. auto-generated fields) */
487
+ skip?: boolean;
486
488
  }
487
489
  /**
488
490
  * Simplified config for ContextualCommandService
package/dist/index.esm.js CHANGED
@@ -3323,7 +3323,7 @@ theme, isOpen, }) {
3323
3323
  }, [onModelSelectionChange]);
3324
3324
  return (jsxs("div", { className: `px-3 py-2 border-t flex flex-col gap-2 transition-all duration-500 delay-500 ${isOpen ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-4'}`, style: { borderColor: theme.colors.border.primary }, children: [attachedFiles.length > 0 && (jsx("div", { className: "flex flex-wrap gap-2 mb-2", children: attachedFiles.map((file, index) => (jsxs("div", { className: "relative group", children: [jsx("div", { className: "w-16 h-16 rounded-lg border border-gray-200 bg-gray-50 flex items-center justify-center overflow-hidden", children: file.type.startsWith('image/') ? (jsx("img", { src: URL.createObjectURL(file), alt: `Attached ${index + 1}`, className: "w-full h-full object-cover" })) : (jsx("div", { className: "flex items-center justify-center", children: FileHandler.getFileIcon(file) })) }), jsx("button", { onClick: () => removeFile(index), className: "absolute -top-2 -right-2 w-5 h-5 bg-red-500 text-white rounded-full flex items-center justify-center text-xs hover:bg-red-600 transition-colors", title: "Remove file", children: "\u00D7" }), jsx("div", { className: "absolute bottom-0 left-1/2 transform -translate-x-1/2 translate-y-full opacity-0 group-hover:opacity-100 transition-opacity duration-200 pointer-events-none z-10 mt-2", children: jsxs("div", { className: "bg-gray-900 text-white text-xs rounded-lg px-2 py-1 whitespace-nowrap shadow-lg", children: [jsx("div", { className: "font-medium truncate max-w-32", title: file.name, children: file.name }), jsxs("div", { className: "text-gray-300", children: [FileHandler.getFileTypeDescription(file), " \u2022", ' ', FileHandler.formatFileSize(file.size)] }), jsx("div", { className: "absolute -top-1 left-1/2 transform -translate-x-1/2 w-2 h-2 bg-gray-900 rotate-45" })] }) })] }, index))) })), incompatibleFiles.length > 0 && (jsxs("div", { className: "relative flex flex-col gap-1 text-sm text-orange-700 bg-orange-50 border border-orange-200 rounded px-3 py-2 mb-2", children: [jsx("button", { onClick: () => setIncompatibleFiles([]), className: "absolute top-1 right-1 w-5 h-5 flex items-center justify-center text-orange-500 hover:text-orange-700 hover:bg-orange-200 rounded-full transition-colors", title: "Dismiss", type: "button", children: "\u00D7" }), jsxs("div", { className: "flex items-center gap-2 pr-6", children: [jsx("span", { children: "\u26A0\uFE0F" }), jsx("span", { className: "font-medium", children: incompatibleFiles.length === 1
3325
3325
  ? 'File not supported'
3326
- : 'Some files not supported' })] }), jsxs("div", { className: "text-xs", children: [jsx("div", { className: "mb-1", children: "These files were skipped:" }), jsxs("ul", { className: "list-disc list-inside ml-2 space-y-0.5", children: [incompatibleFiles.slice(0, 3).map((fileName, index) => (jsx("li", { className: "truncate", children: fileName }, index))), incompatibleFiles.length > 3 && (jsxs("li", { children: ["... and ", incompatibleFiles.length - 3, " more"] }))] }), jsxs("div", { className: "mt-1 text-orange-600", children: ["\uD83D\uDCA1 Only ", FileHandler.getAcceptedTypesDescription(), " are supported", incompatibleFiles.some((name) => name.includes('images not supported by current model')) && (jsxs("div", { className: "mt-1", children: ["\uD83D\uDD04 ", jsx("strong", { children: "Switch to GPT-4O, Claude 3, or Gemini" }), " to enable image uploads"] }))] })] })] })), jsxs("div", { className: `relative flex flex-col gap-1 rounded border px-2 pt-1 pb-1 cursor-text transition-all duration-200 border-2 focus-within:shadow-sm ${isDragOver ? 'border-dashed bg-opacity-20' : 'border-transparent'}`, style: {
3326
+ : 'Some files not supported' })] }), jsxs("div", { className: "text-xs", children: [jsx("div", { className: "mb-1", children: "These files were skipped:" }), jsxs("ul", { className: "list-disc list-inside ml-2 space-y-0.5", children: [incompatibleFiles.slice(0, 3).map((fileName, index) => (jsx("li", { className: "truncate", children: fileName }, index))), incompatibleFiles.length > 3 && (jsxs("li", { children: ["... and ", incompatibleFiles.length - 3, " more"] }))] }), jsxs("div", { className: "mt-1 text-orange-600", children: ["\uD83D\uDCA1 Only ", FileHandler.getAcceptedTypesDescription(), " are supported", incompatibleFiles.some((name) => name.includes('images not supported by current model')) && (jsx("div", { className: "mt-1", children: "\uD83D\uDD04 Switch to a model showing the image icon in the model switcher to enable image uploads" }))] })] })] })), jsxs("div", { className: `relative flex flex-col gap-1 rounded border px-2 pt-1 pb-1 cursor-text transition-all duration-200 border-2 focus-within:shadow-sm ${isDragOver ? 'border-dashed bg-opacity-20' : 'border-transparent'}`, style: {
3327
3327
  backgroundColor: theme.colors.surface.primary,
3328
3328
  borderColor: isDragOver
3329
3329
  ? theme.colors.primary[400]
@@ -3350,7 +3350,7 @@ theme, isOpen, }) {
3350
3350
  e.currentTarget.style.color = theme.colors.text.tertiary;
3351
3351
  }, title: imageSupported
3352
3352
  ? 'Attach images - AI can analyze image content'
3353
- : "Current model doesn't support images. Switch to GPT-4O, Claude 3, or Gemini to use image attachments.", tabIndex: -1, type: "button", onClick: () => imageSupported && imageInputRef.current?.click(), disabled: !imageSupported, children: jsx(Icon, { name: "image", size: "sm" }) })), jsx("button", { className: "p-1 cursor-pointer disabled:opacity-50 disabled:cursor-default transition-colors", style: { color: theme.colors.text.tertiary }, title: "Record audio (coming soon)", tabIndex: -1, type: "button", onClick: handleAudioRecord, disabled: true, children: jsx(Icon, { name: "microphone", size: "sm" }) })] }), jsx("button", { onClick: () => onSend(), disabled: (!query.trim() && attachedFiles.length === 0) || isLoading, className: "rounded-full transition disabled:opacity-50 p-2", style: {
3353
+ : "Current model doesn't support images. Switch to GPT-4O, Claude, or Gemini to use image attachments.", tabIndex: -1, type: "button", onClick: () => imageSupported && imageInputRef.current?.click(), disabled: !imageSupported, children: jsx(Icon, { name: "image", size: "sm" }) })), jsx("button", { className: "p-1 cursor-pointer disabled:opacity-50 disabled:cursor-default transition-colors", style: { color: theme.colors.text.tertiary }, title: "Record audio (coming soon)", tabIndex: -1, type: "button", onClick: handleAudioRecord, disabled: true, children: jsx(Icon, { name: "microphone", size: "sm" }) })] }), jsx("button", { onClick: () => onSend(), disabled: (!query.trim() && attachedFiles.length === 0) || isLoading, className: "rounded-full transition disabled:opacity-50 p-2", style: {
3354
3354
  color: theme.colors.text.primary,
3355
3355
  }, onMouseEnter: (e) => {
3356
3356
  if (!e.currentTarget.disabled) {
@@ -3365,7 +3365,7 @@ theme, isOpen, }) {
3365
3365
  features.imageAnalysis !== false &&
3366
3366
  features.enableImageUploads !== false &&
3367
3367
  !imageSupported &&
3368
- !imageTipDismissed && (jsxs("div", { className: "relative px-2 py-1 bg-amber-50 border border-amber-200 rounded text-amber-700 text-xs flex items-center gap-2", children: [jsx(Icon, { name: "image", size: "xs", className: "opacity-50" }), jsxs("span", { className: "flex-1 pr-4", children: ["\uD83D\uDCA1 ", jsx("strong", { children: "Tip:" }), " Switch to GPT-4O, Claude 3, or Gemini in the model switcher below to enable image attachments"] }), jsx("button", { onClick: () => setImageTipDismissed(true), className: "absolute top-1 right-1 w-4 h-4 flex items-center justify-center text-amber-500 hover:text-amber-700 hover:bg-amber-200 rounded-full transition-colors text-xs font-bold", title: "Dismiss tip", type: "button", children: "\u00D7" })] })), jsxs("div", { className: "flex items-center justify-between text-xs px-0 pt-0", style: { color: theme.colors.text.tertiary }, children: [jsx("div", { className: "flex gap-4", children: features.modelSwitching !== false && (jsx(ModelSwitcher, { models: models, defaultModel: defaultModel, showUsageStats: features.usageTracking !== false && showUsageStats !== false, theme: theme, onModelSelectionChange: modelSelectionHandler })) }), jsx("div", { className: "flex items-center gap-2", children: jsxs("span", { children: [jsx("kbd", { className: "px-1 rounded", style: {
3368
+ !imageTipDismissed && (jsxs("div", { className: "relative px-2 py-1 bg-amber-50 border border-amber-200 rounded text-amber-700 text-xs flex items-center gap-2", children: [jsx(Icon, { name: "image", size: "xs", className: "opacity-50" }), jsxs("span", { className: "flex-1 pr-4", children: ["\uD83D\uDCA1 ", jsx("strong", { children: "Tip:" }), " Switch to a model showing the image icon in the model switcher below to enable image uploads"] }), jsx("button", { onClick: () => setImageTipDismissed(true), className: "absolute top-1 right-1 w-4 h-4 flex items-center justify-center text-amber-500 hover:text-amber-700 hover:bg-amber-200 rounded-full transition-colors text-xs font-bold", title: "Dismiss tip", type: "button", children: "\u00D7" })] })), jsxs("div", { className: "flex items-center justify-between text-xs px-0 pt-0", style: { color: theme.colors.text.tertiary }, children: [jsx("div", { className: "flex gap-4", children: features.modelSwitching !== false && (jsx(ModelSwitcher, { models: models, defaultModel: defaultModel, showUsageStats: features.usageTracking !== false && showUsageStats !== false, theme: theme, onModelSelectionChange: modelSelectionHandler })) }), jsx("div", { className: "flex items-center gap-2", children: jsxs("span", { children: [jsx("kbd", { className: "px-1 rounded", style: {
3369
3369
  backgroundColor: theme.colors.surface.secondary,
3370
3370
  color: theme.colors.text.secondary,
3371
3371
  }, children: "\u23CE" }), ' ', "to send,", ' ', jsx("kbd", { className: "px-1 rounded", style: {
package/dist/index.js CHANGED
@@ -3325,7 +3325,7 @@ theme, isOpen, }) {
3325
3325
  }, [onModelSelectionChange]);
3326
3326
  return (jsxRuntime.jsxs("div", { className: `px-3 py-2 border-t flex flex-col gap-2 transition-all duration-500 delay-500 ${isOpen ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-4'}`, style: { borderColor: theme.colors.border.primary }, children: [attachedFiles.length > 0 && (jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2 mb-2", children: attachedFiles.map((file, index) => (jsxRuntime.jsxs("div", { className: "relative group", children: [jsxRuntime.jsx("div", { className: "w-16 h-16 rounded-lg border border-gray-200 bg-gray-50 flex items-center justify-center overflow-hidden", children: file.type.startsWith('image/') ? (jsxRuntime.jsx("img", { src: URL.createObjectURL(file), alt: `Attached ${index + 1}`, className: "w-full h-full object-cover" })) : (jsxRuntime.jsx("div", { className: "flex items-center justify-center", children: FileHandler.getFileIcon(file) })) }), jsxRuntime.jsx("button", { onClick: () => removeFile(index), className: "absolute -top-2 -right-2 w-5 h-5 bg-red-500 text-white rounded-full flex items-center justify-center text-xs hover:bg-red-600 transition-colors", title: "Remove file", children: "\u00D7" }), jsxRuntime.jsx("div", { className: "absolute bottom-0 left-1/2 transform -translate-x-1/2 translate-y-full opacity-0 group-hover:opacity-100 transition-opacity duration-200 pointer-events-none z-10 mt-2", children: jsxRuntime.jsxs("div", { className: "bg-gray-900 text-white text-xs rounded-lg px-2 py-1 whitespace-nowrap shadow-lg", children: [jsxRuntime.jsx("div", { className: "font-medium truncate max-w-32", title: file.name, children: file.name }), jsxRuntime.jsxs("div", { className: "text-gray-300", children: [FileHandler.getFileTypeDescription(file), " \u2022", ' ', FileHandler.formatFileSize(file.size)] }), jsxRuntime.jsx("div", { className: "absolute -top-1 left-1/2 transform -translate-x-1/2 w-2 h-2 bg-gray-900 rotate-45" })] }) })] }, index))) })), incompatibleFiles.length > 0 && (jsxRuntime.jsxs("div", { className: "relative flex flex-col gap-1 text-sm text-orange-700 bg-orange-50 border border-orange-200 rounded px-3 py-2 mb-2", children: [jsxRuntime.jsx("button", { onClick: () => setIncompatibleFiles([]), className: "absolute top-1 right-1 w-5 h-5 flex items-center justify-center text-orange-500 hover:text-orange-700 hover:bg-orange-200 rounded-full transition-colors", title: "Dismiss", type: "button", children: "\u00D7" }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2 pr-6", children: [jsxRuntime.jsx("span", { children: "\u26A0\uFE0F" }), jsxRuntime.jsx("span", { className: "font-medium", children: incompatibleFiles.length === 1
3327
3327
  ? 'File not supported'
3328
- : 'Some files not supported' })] }), jsxRuntime.jsxs("div", { className: "text-xs", children: [jsxRuntime.jsx("div", { className: "mb-1", children: "These files were skipped:" }), jsxRuntime.jsxs("ul", { className: "list-disc list-inside ml-2 space-y-0.5", children: [incompatibleFiles.slice(0, 3).map((fileName, index) => (jsxRuntime.jsx("li", { className: "truncate", children: fileName }, index))), incompatibleFiles.length > 3 && (jsxRuntime.jsxs("li", { children: ["... and ", incompatibleFiles.length - 3, " more"] }))] }), jsxRuntime.jsxs("div", { className: "mt-1 text-orange-600", children: ["\uD83D\uDCA1 Only ", FileHandler.getAcceptedTypesDescription(), " are supported", incompatibleFiles.some((name) => name.includes('images not supported by current model')) && (jsxRuntime.jsxs("div", { className: "mt-1", children: ["\uD83D\uDD04 ", jsxRuntime.jsx("strong", { children: "Switch to GPT-4O, Claude 3, or Gemini" }), " to enable image uploads"] }))] })] })] })), jsxRuntime.jsxs("div", { className: `relative flex flex-col gap-1 rounded border px-2 pt-1 pb-1 cursor-text transition-all duration-200 border-2 focus-within:shadow-sm ${isDragOver ? 'border-dashed bg-opacity-20' : 'border-transparent'}`, style: {
3328
+ : 'Some files not supported' })] }), jsxRuntime.jsxs("div", { className: "text-xs", children: [jsxRuntime.jsx("div", { className: "mb-1", children: "These files were skipped:" }), jsxRuntime.jsxs("ul", { className: "list-disc list-inside ml-2 space-y-0.5", children: [incompatibleFiles.slice(0, 3).map((fileName, index) => (jsxRuntime.jsx("li", { className: "truncate", children: fileName }, index))), incompatibleFiles.length > 3 && (jsxRuntime.jsxs("li", { children: ["... and ", incompatibleFiles.length - 3, " more"] }))] }), jsxRuntime.jsxs("div", { className: "mt-1 text-orange-600", children: ["\uD83D\uDCA1 Only ", FileHandler.getAcceptedTypesDescription(), " are supported", incompatibleFiles.some((name) => name.includes('images not supported by current model')) && (jsxRuntime.jsx("div", { className: "mt-1", children: "\uD83D\uDD04 Switch to a model showing the image icon in the model switcher to enable image uploads" }))] })] })] })), jsxRuntime.jsxs("div", { className: `relative flex flex-col gap-1 rounded border px-2 pt-1 pb-1 cursor-text transition-all duration-200 border-2 focus-within:shadow-sm ${isDragOver ? 'border-dashed bg-opacity-20' : 'border-transparent'}`, style: {
3329
3329
  backgroundColor: theme.colors.surface.primary,
3330
3330
  borderColor: isDragOver
3331
3331
  ? theme.colors.primary[400]
@@ -3352,7 +3352,7 @@ theme, isOpen, }) {
3352
3352
  e.currentTarget.style.color = theme.colors.text.tertiary;
3353
3353
  }, title: imageSupported
3354
3354
  ? 'Attach images - AI can analyze image content'
3355
- : "Current model doesn't support images. Switch to GPT-4O, Claude 3, or Gemini to use image attachments.", tabIndex: -1, type: "button", onClick: () => imageSupported && imageInputRef.current?.click(), disabled: !imageSupported, children: jsxRuntime.jsx(Icon, { name: "image", size: "sm" }) })), jsxRuntime.jsx("button", { className: "p-1 cursor-pointer disabled:opacity-50 disabled:cursor-default transition-colors", style: { color: theme.colors.text.tertiary }, title: "Record audio (coming soon)", tabIndex: -1, type: "button", onClick: handleAudioRecord, disabled: true, children: jsxRuntime.jsx(Icon, { name: "microphone", size: "sm" }) })] }), jsxRuntime.jsx("button", { onClick: () => onSend(), disabled: (!query.trim() && attachedFiles.length === 0) || isLoading, className: "rounded-full transition disabled:opacity-50 p-2", style: {
3355
+ : "Current model doesn't support images. Switch to GPT-4O, Claude, or Gemini to use image attachments.", tabIndex: -1, type: "button", onClick: () => imageSupported && imageInputRef.current?.click(), disabled: !imageSupported, children: jsxRuntime.jsx(Icon, { name: "image", size: "sm" }) })), jsxRuntime.jsx("button", { className: "p-1 cursor-pointer disabled:opacity-50 disabled:cursor-default transition-colors", style: { color: theme.colors.text.tertiary }, title: "Record audio (coming soon)", tabIndex: -1, type: "button", onClick: handleAudioRecord, disabled: true, children: jsxRuntime.jsx(Icon, { name: "microphone", size: "sm" }) })] }), jsxRuntime.jsx("button", { onClick: () => onSend(), disabled: (!query.trim() && attachedFiles.length === 0) || isLoading, className: "rounded-full transition disabled:opacity-50 p-2", style: {
3356
3356
  color: theme.colors.text.primary,
3357
3357
  }, onMouseEnter: (e) => {
3358
3358
  if (!e.currentTarget.disabled) {
@@ -3367,7 +3367,7 @@ theme, isOpen, }) {
3367
3367
  features.imageAnalysis !== false &&
3368
3368
  features.enableImageUploads !== false &&
3369
3369
  !imageSupported &&
3370
- !imageTipDismissed && (jsxRuntime.jsxs("div", { className: "relative px-2 py-1 bg-amber-50 border border-amber-200 rounded text-amber-700 text-xs flex items-center gap-2", children: [jsxRuntime.jsx(Icon, { name: "image", size: "xs", className: "opacity-50" }), jsxRuntime.jsxs("span", { className: "flex-1 pr-4", children: ["\uD83D\uDCA1 ", jsxRuntime.jsx("strong", { children: "Tip:" }), " Switch to GPT-4O, Claude 3, or Gemini in the model switcher below to enable image attachments"] }), jsxRuntime.jsx("button", { onClick: () => setImageTipDismissed(true), className: "absolute top-1 right-1 w-4 h-4 flex items-center justify-center text-amber-500 hover:text-amber-700 hover:bg-amber-200 rounded-full transition-colors text-xs font-bold", title: "Dismiss tip", type: "button", children: "\u00D7" })] })), jsxRuntime.jsxs("div", { className: "flex items-center justify-between text-xs px-0 pt-0", style: { color: theme.colors.text.tertiary }, children: [jsxRuntime.jsx("div", { className: "flex gap-4", children: features.modelSwitching !== false && (jsxRuntime.jsx(ModelSwitcher, { models: models, defaultModel: defaultModel, showUsageStats: features.usageTracking !== false && showUsageStats !== false, theme: theme, onModelSelectionChange: modelSelectionHandler })) }), jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: jsxRuntime.jsxs("span", { children: [jsxRuntime.jsx("kbd", { className: "px-1 rounded", style: {
3370
+ !imageTipDismissed && (jsxRuntime.jsxs("div", { className: "relative px-2 py-1 bg-amber-50 border border-amber-200 rounded text-amber-700 text-xs flex items-center gap-2", children: [jsxRuntime.jsx(Icon, { name: "image", size: "xs", className: "opacity-50" }), jsxRuntime.jsxs("span", { className: "flex-1 pr-4", children: ["\uD83D\uDCA1 ", jsxRuntime.jsx("strong", { children: "Tip:" }), " Switch to a model showing the image icon in the model switcher below to enable image uploads"] }), jsxRuntime.jsx("button", { onClick: () => setImageTipDismissed(true), className: "absolute top-1 right-1 w-4 h-4 flex items-center justify-center text-amber-500 hover:text-amber-700 hover:bg-amber-200 rounded-full transition-colors text-xs font-bold", title: "Dismiss tip", type: "button", children: "\u00D7" })] })), jsxRuntime.jsxs("div", { className: "flex items-center justify-between text-xs px-0 pt-0", style: { color: theme.colors.text.tertiary }, children: [jsxRuntime.jsx("div", { className: "flex gap-4", children: features.modelSwitching !== false && (jsxRuntime.jsx(ModelSwitcher, { models: models, defaultModel: defaultModel, showUsageStats: features.usageTracking !== false && showUsageStats !== false, theme: theme, onModelSelectionChange: modelSelectionHandler })) }), jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: jsxRuntime.jsxs("span", { children: [jsxRuntime.jsx("kbd", { className: "px-1 rounded", style: {
3371
3371
  backgroundColor: theme.colors.surface.secondary,
3372
3372
  color: theme.colors.text.secondary,
3373
3373
  }, children: "\u23CE" }), ' ', "to send,", ' ', jsxRuntime.jsx("kbd", { className: "px-1 rounded", style: {
@@ -24,6 +24,7 @@ export declare class ContextualCommandService {
24
24
  private buildContextualSystemPrompt;
25
25
  /**
26
26
  * Format schema fields into readable descriptions
27
+ * Excludes client-generated fields from the output
27
28
  */
28
29
  private formatSchemaFields;
29
30
  /**
@@ -8231,6 +8231,10 @@ function sanitizeFormData(formData, schema) {
8231
8231
  // If schema is provided, use it for validation
8232
8232
  if (schema && schema.properties && schema.properties[key]) {
8233
8233
  const fieldSchema = schema.properties[key];
8234
+ // Skip client-generated fields - they should not be included in formState
8235
+ if (fieldSchema.skip) {
8236
+ return; // Skip this field
8237
+ }
8234
8238
  sanitized[key] = validateAndConvertField(value, fieldSchema);
8235
8239
  }
8236
8240
  else {
@@ -13486,6 +13490,7 @@ ${allRoutesInfo}
13486
13490
  - Match exact field names and types from the chosen schema
13487
13491
  - Respect required vs optional fields
13488
13492
  - If a field has enum values, only use those exact values
13493
+ - **DO NOT generate fields marked with skip: true** - these are auto-generated on the client side and should never appear in your suggestions
13489
13494
 
13490
13495
  **🚨 CRITICAL CURRENCY FORMATTING:**
13491
13496
  - ALL currency amounts (amount, buyRate, sellRate) MUST be NUMBERS in CENTS
@@ -13565,6 +13570,7 @@ ${this.formatSchemaFields(singleSchema)}${routesInfo}
13565
13570
  - For nested objects/arrays, follow the nested schema structure
13566
13571
  - If a field has enum values, only use those exact values
13567
13572
  - When suggesting navigation, use the routes defined in the schema above
13573
+ - **DO NOT generate fields marked with skip: true** - these are auto-generated on the client side and should never appear in your suggestions
13568
13574
 
13569
13575
  **🚨 CRITICAL CURRENCY FORMATTING:**
13570
13576
  - ALL currency amounts (amount, buyRate, sellRate) MUST be NUMBERS in CENTS
@@ -13589,10 +13595,17 @@ ${additionalContext}
13589
13595
  }
13590
13596
  /**
13591
13597
  * Format schema fields into readable descriptions
13598
+ * Excludes client-generated fields from the output
13592
13599
  */
13593
13600
  formatSchemaFields(schema) {
13594
13601
  const fields = [];
13602
+ const clientGeneratedFields = [];
13595
13603
  for (const [fieldName, fieldDef] of Object.entries(schema.properties || {})) {
13604
+ // Skip client-generated fields - they should not be shown to AI
13605
+ if (typeof fieldDef === 'object' && fieldDef.skip) {
13606
+ clientGeneratedFields.push(fieldName);
13607
+ continue;
13608
+ }
13596
13609
  const required = schema.required?.includes(fieldName) ? '**REQUIRED**' : 'optional';
13597
13610
  const type = typeof fieldDef === 'object' ? fieldDef.type || 'unknown' : 'unknown';
13598
13611
  const description = typeof fieldDef === 'object' ? fieldDef.description || '' : '';
@@ -13601,6 +13614,10 @@ ${additionalContext}
13601
13614
  : '';
13602
13615
  fields.push(`- **${fieldName}** (${type}) ${required}${enumValues}${description ? `: ${description}` : ''}`);
13603
13616
  }
13617
+ // Add note about client-generated fields if any exist
13618
+ if (clientGeneratedFields.length > 0) {
13619
+ fields.push(`\n**NOTE:** The following fields are auto-generated on the client side and should NOT be included in your suggestions: ${clientGeneratedFields.join(', ')}`);
13620
+ }
13604
13621
  return fields.join('\n');
13605
13622
  }
13606
13623
  /**
@@ -8251,6 +8251,10 @@ function sanitizeFormData(formData, schema) {
8251
8251
  // If schema is provided, use it for validation
8252
8252
  if (schema && schema.properties && schema.properties[key]) {
8253
8253
  const fieldSchema = schema.properties[key];
8254
+ // Skip client-generated fields - they should not be included in formState
8255
+ if (fieldSchema.skip) {
8256
+ return; // Skip this field
8257
+ }
8254
8258
  sanitized[key] = validateAndConvertField(value, fieldSchema);
8255
8259
  }
8256
8260
  else {
@@ -13506,6 +13510,7 @@ ${allRoutesInfo}
13506
13510
  - Match exact field names and types from the chosen schema
13507
13511
  - Respect required vs optional fields
13508
13512
  - If a field has enum values, only use those exact values
13513
+ - **DO NOT generate fields marked with skip: true** - these are auto-generated on the client side and should never appear in your suggestions
13509
13514
 
13510
13515
  **🚨 CRITICAL CURRENCY FORMATTING:**
13511
13516
  - ALL currency amounts (amount, buyRate, sellRate) MUST be NUMBERS in CENTS
@@ -13585,6 +13590,7 @@ ${this.formatSchemaFields(singleSchema)}${routesInfo}
13585
13590
  - For nested objects/arrays, follow the nested schema structure
13586
13591
  - If a field has enum values, only use those exact values
13587
13592
  - When suggesting navigation, use the routes defined in the schema above
13593
+ - **DO NOT generate fields marked with skip: true** - these are auto-generated on the client side and should never appear in your suggestions
13588
13594
 
13589
13595
  **🚨 CRITICAL CURRENCY FORMATTING:**
13590
13596
  - ALL currency amounts (amount, buyRate, sellRate) MUST be NUMBERS in CENTS
@@ -13609,10 +13615,17 @@ ${additionalContext}
13609
13615
  }
13610
13616
  /**
13611
13617
  * Format schema fields into readable descriptions
13618
+ * Excludes client-generated fields from the output
13612
13619
  */
13613
13620
  formatSchemaFields(schema) {
13614
13621
  const fields = [];
13622
+ const clientGeneratedFields = [];
13615
13623
  for (const [fieldName, fieldDef] of Object.entries(schema.properties || {})) {
13624
+ // Skip client-generated fields - they should not be shown to AI
13625
+ if (typeof fieldDef === 'object' && fieldDef.skip) {
13626
+ clientGeneratedFields.push(fieldName);
13627
+ continue;
13628
+ }
13616
13629
  const required = schema.required?.includes(fieldName) ? '**REQUIRED**' : 'optional';
13617
13630
  const type = typeof fieldDef === 'object' ? fieldDef.type || 'unknown' : 'unknown';
13618
13631
  const description = typeof fieldDef === 'object' ? fieldDef.description || '' : '';
@@ -13621,6 +13634,10 @@ ${additionalContext}
13621
13634
  : '';
13622
13635
  fields.push(`- **${fieldName}** (${type}) ${required}${enumValues}${description ? `: ${description}` : ''}`);
13623
13636
  }
13637
+ // Add note about client-generated fields if any exist
13638
+ if (clientGeneratedFields.length > 0) {
13639
+ fields.push(`\n**NOTE:** The following fields are auto-generated on the client side and should NOT be included in your suggestions: ${clientGeneratedFields.join(', ')}`);
13640
+ }
13624
13641
  return fields.join('\n');
13625
13642
  }
13626
13643
  /**
@@ -24,6 +24,7 @@ export declare class ContextualCommandService {
24
24
  private buildContextualSystemPrompt;
25
25
  /**
26
26
  * Format schema fields into readable descriptions
27
+ * Excludes client-generated fields from the output
27
28
  */
28
29
  private formatSchemaFields;
29
30
  /**
@@ -483,6 +483,8 @@ export interface SchemaProperty {
483
483
  maxLength?: number;
484
484
  minimum?: number;
485
485
  maximum?: number;
486
+ /** If true, this field is not to be generated by AI (e.g. auto-generated fields) */
487
+ skip?: boolean;
486
488
  }
487
489
  /**
488
490
  * Simplified config for ContextualCommandService
@@ -483,6 +483,8 @@ export interface SchemaProperty {
483
483
  maxLength?: number;
484
484
  minimum?: number;
485
485
  maximum?: number;
486
+ /** If true, this field is not to be generated by AI (e.g. auto-generated fields) */
487
+ skip?: boolean;
486
488
  }
487
489
  /**
488
490
  * Simplified config for ContextualCommandService
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orchid-ai",
3
- "version": "1.2.8",
3
+ "version": "1.3.0",
4
4
  "type": "module",
5
5
  "description": "AI-powered command processing and chat interface for React applications",
6
6
  "main": "dist/index.js",