@open-mercato/core 0.6.1-develop.3291.1.6fad645fd0 → 0.6.1-develop.3306.1.9ad9ff2526

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 (122) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +14 -0
  3. package/dist/modules/auth/backend/roles/[id]/edit/page.js +2 -1
  4. package/dist/modules/auth/backend/roles/[id]/edit/page.js.map +2 -2
  5. package/dist/modules/auth/backend/users/[id]/edit/page.js +2 -5
  6. package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
  7. package/dist/modules/catalog/ai-agents.js +47 -5
  8. package/dist/modules/catalog/ai-agents.js.map +2 -2
  9. package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js +2 -5
  10. package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js.map +2 -2
  11. package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js +4 -3
  12. package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js.map +2 -2
  13. package/dist/modules/catalog/backend/catalog/products/[id]/page.js +2 -9
  14. package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
  15. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +2 -9
  16. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
  17. package/dist/modules/customers/ai-agents.js +174 -1
  18. package/dist/modules/customers/ai-agents.js.map +2 -2
  19. package/dist/modules/customers/ai-tools/deal-analyzer-pack.js +196 -0
  20. package/dist/modules/customers/ai-tools/deal-analyzer-pack.js.map +7 -0
  21. package/dist/modules/customers/ai-tools.js +3 -1
  22. package/dist/modules/customers/ai-tools.js.map +2 -2
  23. package/dist/modules/customers/backend/customers/companies/page.js +11 -1
  24. package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
  25. package/dist/modules/customers/backend/customers/deals/page.js +11 -1
  26. package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
  27. package/dist/modules/customers/backend/customers/people/page.js +11 -1
  28. package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
  29. package/dist/modules/customers/commands/companies.js +37 -15
  30. package/dist/modules/customers/commands/companies.js.map +2 -2
  31. package/dist/modules/customers/components/detail/AiActionChips.js +2 -2
  32. package/dist/modules/customers/components/detail/AiActionChips.js.map +2 -2
  33. package/dist/modules/customers/components/detail/ChangelogTab.js +3 -9
  34. package/dist/modules/customers/components/detail/ChangelogTab.js.map +2 -2
  35. package/dist/modules/customers/components/detail/changelogValues.js +35 -0
  36. package/dist/modules/customers/components/detail/changelogValues.js.map +7 -0
  37. package/dist/modules/customers/components/detail/customFieldUtils.js +1 -1
  38. package/dist/modules/customers/components/detail/customFieldUtils.js.map +1 -1
  39. package/dist/modules/customers/components/formConfig.js +3 -2
  40. package/dist/modules/customers/components/formConfig.js.map +2 -2
  41. package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.js +4 -9
  42. package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.js.map +2 -2
  43. package/dist/modules/customers/widgets/injection/ai-deal-analyzer-trigger/widget.client.js +302 -0
  44. package/dist/modules/customers/widgets/injection/ai-deal-analyzer-trigger/widget.client.js.map +7 -0
  45. package/dist/modules/customers/widgets/injection/ai-deal-analyzer-trigger/widget.js +17 -0
  46. package/dist/modules/customers/widgets/injection/ai-deal-analyzer-trigger/widget.js.map +7 -0
  47. package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.client.js +2 -2
  48. package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.client.js.map +2 -2
  49. package/dist/modules/customers/widgets/injection-table.js +2 -2
  50. package/dist/modules/customers/widgets/injection-table.js.map +2 -2
  51. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js +2 -5
  52. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js.map +2 -2
  53. package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js +2 -5
  54. package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js.map +2 -2
  55. package/dist/modules/resources/backend/resources/resources/[id]/page.js +2 -5
  56. package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
  57. package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js +2 -25
  58. package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js.map +2 -2
  59. package/dist/modules/sales/components/channels/ChannelOfferForm.js +2 -43
  60. package/dist/modules/sales/components/channels/ChannelOfferForm.js.map +2 -2
  61. package/dist/modules/sales/components/documents/LineItemDialog.js +162 -42
  62. package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
  63. package/dist/modules/sales/components/documents/customFieldHelpers.js +4 -31
  64. package/dist/modules/sales/components/documents/customFieldHelpers.js.map +2 -2
  65. package/package.json +15 -6
  66. package/src/modules/auth/backend/roles/[id]/edit/page.tsx +2 -1
  67. package/src/modules/auth/backend/users/[id]/edit/page.tsx +2 -5
  68. package/src/modules/business_rules/migrations/.snapshot-open-mercato.json +746 -394
  69. package/src/modules/catalog/ai-agents.ts +62 -4
  70. package/src/modules/catalog/backend/catalog/categories/[id]/edit/page.tsx +2 -5
  71. package/src/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.tsx +4 -3
  72. package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +2 -12
  73. package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +2 -10
  74. package/src/modules/catalog/migrations/.snapshot-open-mercato.json +2519 -1307
  75. package/src/modules/customer_accounts/migrations/.snapshot-open-mercato.json +828 -834
  76. package/src/modules/customers/AGENTS.md +6 -1
  77. package/src/modules/customers/ai-agents.ts +213 -6
  78. package/src/modules/customers/ai-tools/deal-analyzer-pack.ts +286 -0
  79. package/src/modules/customers/ai-tools.ts +2 -0
  80. package/src/modules/customers/backend/customers/companies/page.tsx +10 -0
  81. package/src/modules/customers/backend/customers/deals/page.tsx +10 -0
  82. package/src/modules/customers/backend/customers/people/page.tsx +10 -0
  83. package/src/modules/customers/commands/companies.ts +38 -14
  84. package/src/modules/customers/components/detail/AiActionChips.tsx +2 -2
  85. package/src/modules/customers/components/detail/ChangelogTab.tsx +3 -10
  86. package/src/modules/customers/components/detail/changelogValues.ts +42 -0
  87. package/src/modules/customers/components/detail/customFieldUtils.ts +1 -1
  88. package/src/modules/customers/components/formConfig.tsx +3 -2
  89. package/src/modules/customers/i18n/de.json +7 -0
  90. package/src/modules/customers/i18n/en.json +7 -0
  91. package/src/modules/customers/i18n/es.json +7 -0
  92. package/src/modules/customers/i18n/pl.json +7 -0
  93. package/src/modules/customers/migrations/.snapshot-open-mercato.json +2313 -2336
  94. package/src/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.tsx +4 -6
  95. package/src/modules/customers/widgets/injection/ai-deal-analyzer-trigger/widget.client.tsx +358 -0
  96. package/src/modules/customers/widgets/injection/ai-deal-analyzer-trigger/widget.ts +34 -0
  97. package/src/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.client.tsx +2 -2
  98. package/src/modules/customers/widgets/injection-table.ts +12 -9
  99. package/src/modules/data_sync/migrations/.snapshot-open-mercato.json +554 -210
  100. package/src/modules/dictionaries/migrations/.snapshot-open-mercato.json +146 -146
  101. package/src/modules/directory/backend/directory/organizations/[id]/edit/page.tsx +2 -5
  102. package/src/modules/directory/backend/directory/tenants/[id]/edit/page.tsx +2 -5
  103. package/src/modules/directory/migrations/.snapshot-open-mercato.json +273 -140
  104. package/src/modules/feature_toggles/migrations/.snapshot-open-mercato.json +242 -137
  105. package/src/modules/integrations/migrations/.snapshot-open-mercato.json +498 -195
  106. package/src/modules/payment_gateways/migrations/.snapshot-open-mercato.json +158 -157
  107. package/src/modules/perspectives/migrations/.snapshot-open-mercato.json +274 -129
  108. package/src/modules/planner/migrations/.snapshot-open-mercato.json +327 -157
  109. package/src/modules/progress/AGENTS.md +72 -0
  110. package/src/modules/resources/backend/resources/resources/[id]/page.tsx +2 -5
  111. package/src/modules/resources/migrations/.snapshot-open-mercato.json +920 -470
  112. package/src/modules/sales/backend/sales/channels/[channelId]/edit/page.tsx +2 -27
  113. package/src/modules/sales/components/channels/ChannelOfferForm.tsx +2 -49
  114. package/src/modules/sales/components/documents/LineItemDialog.tsx +214 -78
  115. package/src/modules/sales/components/documents/customFieldHelpers.ts +4 -43
  116. package/src/modules/sales/i18n/de.json +3 -0
  117. package/src/modules/sales/i18n/en.json +3 -0
  118. package/src/modules/sales/i18n/es.json +3 -0
  119. package/src/modules/sales/i18n/pl.json +3 -0
  120. package/src/modules/sales/migrations/.snapshot-open-mercato.json +4740 -4778
  121. package/src/modules/shipping_carriers/migrations/.snapshot-open-mercato.json +340 -81
  122. package/src/modules/staff/migrations/.snapshot-open-mercato.json +1439 -729
@@ -158,6 +158,10 @@ const PROMPT_SECTIONS: PromptSection[] = [
158
158
  'proactively offer the stats card at the start of an exploration',
159
159
  '("Want me to show a quick catalog overview?") — most operators',
160
160
  'find it useful before drilling in.',
161
+ '',
162
+ 'If the operator asks what they can ask you, requests example questions,',
163
+ 'or asks how you can help, answer directly from these instructions.',
164
+ 'Do not call tools for capability / example-question prompts.',
161
165
  ].join('\n'),
162
166
  },
163
167
  {
@@ -244,6 +248,60 @@ function compilePromptTemplate(template: PromptTemplate): string {
244
248
  .join('\n\n')
245
249
  }
246
250
 
251
+ function textFromMessageContent(content: unknown): string {
252
+ if (typeof content === 'string') return content
253
+ if (!Array.isArray(content)) return ''
254
+ return content
255
+ .map((part) => {
256
+ if (typeof part === 'string') return part
257
+ if (!part || typeof part !== 'object') return ''
258
+ const record = part as Record<string, unknown>
259
+ return typeof record.text === 'string' ? record.text : ''
260
+ })
261
+ .join(' ')
262
+ }
263
+
264
+ function latestUserTextFromPrepareStepState(state: unknown): string {
265
+ const messages = (state as { messages?: unknown })?.messages
266
+ if (!Array.isArray(messages)) return ''
267
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
268
+ const message = messages[index]
269
+ if (!message || typeof message !== 'object') continue
270
+ const record = message as Record<string, unknown>
271
+ if (record.role !== 'user') continue
272
+ return textFromMessageContent(record.content)
273
+ }
274
+ return ''
275
+ }
276
+
277
+ function isCatalogMetaHelpPrompt(text: string): boolean {
278
+ const normalized = text.toLowerCase()
279
+ if (!normalized.trim()) return false
280
+ const asksForQuestionIdeas =
281
+ (normalized.includes('question') || normalized.includes('questions')) &&
282
+ (normalized.includes('could ask') ||
283
+ normalized.includes('can ask') ||
284
+ normalized.includes('ask you') ||
285
+ normalized.includes('suggest') ||
286
+ normalized.includes('examples'))
287
+ const asksForCapabilities =
288
+ normalized.includes('what can you do') ||
289
+ normalized.includes('how can you help') ||
290
+ normalized.includes('what should i ask') ||
291
+ normalized.includes('what can i ask')
292
+ return asksForQuestionIdeas || asksForCapabilities
293
+ }
294
+
295
+ function buildCatalogAssistantPrepareStep() {
296
+ return async function catalogAssistantPrepareStep(state: unknown) {
297
+ const latestUserText = latestUserTextFromPrepareStepState(state)
298
+ if (isCatalogMetaHelpPrompt(latestUserText)) {
299
+ return { activeTools: [] }
300
+ }
301
+ return undefined
302
+ }
303
+ }
304
+
247
305
  async function resolvePageContext(
248
306
  input: AiAgentPageContextInput,
249
307
  ): Promise<string | null> {
@@ -269,8 +327,10 @@ const agent: AiAgentDefinition = {
269
327
  requiredFeatures: [...REQUIRED_FEATURES],
270
328
  readOnly: true,
271
329
  mutationPolicy: 'read-only',
272
- defaultProvider: 'openai',
273
- defaultModel: 'gpt-5-mini',
330
+ loop: {
331
+ maxSteps: 4,
332
+ prepareStep: buildCatalogAssistantPrepareStep() as NonNullable<AiAgentDefinition['loop']>['prepareStep'],
333
+ },
274
334
  keywords: ['catalog', 'products', 'categories', 'variants', 'prices', 'offers', 'media'],
275
335
  domain: 'catalog',
276
336
  dataCapabilities: {
@@ -463,8 +523,6 @@ const merchandisingAgent: AiAgentDefinition = {
463
523
  // the operator via the pending-action approval card. Per-tenant override
464
524
  // can downgrade to `read-only` to lock writes without a redeploy.
465
525
  mutationPolicy: 'confirm-required',
466
- defaultProvider: 'openai',
467
- defaultModel: 'gpt-5-mini',
468
526
  keywords: ['catalog', 'merchandising', 'products', 'attributes', 'pricing', 'copy'],
469
527
  domain: 'catalog',
470
528
  dataCapabilities: {
@@ -8,6 +8,7 @@ import { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'
8
8
  import { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'
9
9
  import { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'
10
10
  import { useT } from '@open-mercato/shared/lib/i18n/context'
11
+ import { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'
11
12
  import { E } from '#generated/entities.ids.generated'
12
13
  import { CategorySelect } from '../../../../../components/categories/CategorySelect'
13
14
  import { CategorySlugFieldSync } from '../../../../../components/categories/CategorySlugFieldSync'
@@ -95,11 +96,7 @@ export default function EditCatalogCategoryPage({ params }: { params?: { id?: st
95
96
  const record = Array.isArray(result?.items) ? result.items?.[0] : null
96
97
  if (!record) throw new Error(t('catalog.categories.form.errors.notFound', 'Category not found'))
97
98
  if (cancelled) return
98
- const customValues: Record<string, unknown> = {}
99
- for (const [key, value] of Object.entries(record as Record<string, unknown>)) {
100
- if (key.startsWith('cf_')) customValues[key] = value
101
- else if (key.startsWith('cf:')) customValues[`cf_${key.slice(3)}`] = value
102
- }
99
+ const customValues = extractCustomFieldEntries(record as Record<string, unknown>)
103
100
  setInitialValues({
104
101
  id: record.id,
105
102
  name: record.name,
@@ -31,8 +31,9 @@
31
31
  */
32
32
 
33
33
  import * as React from 'react'
34
- import { Boxes, ChevronDown, FileText, Package, PanelRightOpen, PenLine, Sparkles, Tags, TrendingUp } from 'lucide-react'
34
+ import { Boxes, ChevronDown, FileText, Package, PanelRightOpen, PenLine, Tags, TrendingUp } from 'lucide-react'
35
35
  import { AiChat, type AiChatSuggestion, type AiChatContextItem } from '@open-mercato/ui/ai/AiChat'
36
+ import { AiIcon } from '@open-mercato/ui/ai/AiIcon'
36
37
  import { useAiDock } from '@open-mercato/ui/ai/AiDock'
37
38
  import { useAiChatSessions } from '@open-mercato/ui/ai/AiChatSessions'
38
39
  import { ChatPaneTabs } from '@open-mercato/ui/ai/ChatPaneTabs'
@@ -249,7 +250,7 @@ function useMerchandisingAgents(): MerchandisingAgentsState {
249
250
  'catalog.merchandising_assistant.agents.merchandising.description',
250
251
  'Draft copy, normalize attributes, and propose price changes for the current selection.',
251
252
  ),
252
- icon: <Sparkles className="size-4" />,
253
+ icon: <AiIcon className="size-4" />,
253
254
  },
254
255
  ],
255
256
  [t],
@@ -399,7 +400,7 @@ export function MerchandisingAssistantSheet({
399
400
  agents.length > 1 && 'rounded-r-none border-r-0',
400
401
  )}
401
402
  >
402
- <Sparkles className="size-4" aria-hidden />
403
+ <AiIcon className="size-4" />
403
404
  <span>{labelText}</span>
404
405
  {hasSelection ? (
405
406
  <span
@@ -32,6 +32,7 @@ import { TagsInput } from "@open-mercato/ui/backend/inputs/TagsInput";
32
32
  import { Textarea } from "@open-mercato/ui/primitives/textarea";
33
33
  import { DataLoader } from "@open-mercato/ui/primitives/DataLoader";
34
34
  import { cn } from "@open-mercato/shared/lib/utils";
35
+ import { extractCustomFieldEntries } from "@open-mercato/shared/lib/crud/custom-fields-client";
35
36
  import { Spinner } from "@open-mercato/ui/primitives/spinner";
36
37
  import {
37
38
  apiCall,
@@ -619,7 +620,7 @@ export default function EditCatalogProductPage({
619
620
  ? readProductConversionRows(conversionsRes.result?.items)
620
621
  : [];
621
622
  initialConversionsRef.current = conversionRows;
622
- const { customValues } = extractCustomFields(record);
623
+ const customValues = extractCustomFieldEntries(record);
623
624
  const offers = readOfferSnapshots(record);
624
625
  offerSnapshotsRef.current = offers;
625
626
  const channelIds = extractChannelIds(offers);
@@ -2629,17 +2630,6 @@ function readOptionSchema(metadata: Record<string, any>): ProductOptionInput[] {
2629
2630
  .filter((entry): entry is ProductOptionInput => !!entry);
2630
2631
  }
2631
2632
 
2632
- function extractCustomFields(record: Record<string, unknown>): {
2633
- customValues: Record<string, unknown>;
2634
- } {
2635
- const customValues: Record<string, unknown> = {};
2636
- Object.entries(record).forEach(([key, value]) => {
2637
- if (key.startsWith("cf_")) customValues[key] = value;
2638
- else if (key.startsWith("cf:")) customValues[`cf_${key.slice(3)}`] = value;
2639
- });
2640
- return { customValues };
2641
- }
2642
-
2643
2633
  function normalizeIdList(value: unknown): string[] {
2644
2634
  const ids = Array.isArray(value)
2645
2635
  ? value
@@ -10,6 +10,7 @@ import { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customF
10
10
  import { apiCall, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
11
11
  import { flash } from '@open-mercato/ui/backend/FlashMessages'
12
12
  import { useT } from '@open-mercato/shared/lib/i18n/context'
13
+ import { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'
13
14
  import { E } from '#generated/entities.ids.generated'
14
15
  import { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'
15
16
  import {
@@ -182,7 +183,7 @@ export default function EditVariantPage({ params }: { params?: { productId?: str
182
183
  if (draft.priceId) priceIdMap[kindId] = draft.priceId
183
184
  })
184
185
  setExistingPriceIds(priceIdMap)
185
- const customDefaults = extractCustomFieldValues(record)
186
+ const customDefaults = extractCustomFieldEntries(record)
186
187
  let loadedOptionDefinitions: OptionDefinition[] = []
187
188
  if (resolvedProductId) {
188
189
  const productRes = await apiCall<ProductResponse>(
@@ -631,15 +632,6 @@ async function loadVariantPrices(variantId: string, priceKinds: PriceKindSummary
631
632
  return drafts
632
633
  }
633
634
 
634
- function extractCustomFieldValues(record: Record<string, unknown>): Record<string, unknown> {
635
- const customValues: Record<string, unknown> = {}
636
- Object.entries(record).forEach(([key, value]) => {
637
- if (key.startsWith('cf_')) customValues[key] = value
638
- else if (key.startsWith('cf:')) customValues[`cf_${key.slice(3)}`] = value
639
- })
640
- return customValues
641
- }
642
-
643
635
  async function syncVariantPricesUpdate({
644
636
  priceKinds,
645
637
  priceDrafts,