Commit graph

6 commits

Author SHA1 Message Date
c19637465b feat: Frappe ERP matching, pipeline model cache, ACL, stock field, specs by type
Frappe ERP:
- findExistingCustomer() on FrappeErpAdapter — two-step name+address lookup
- FrappeHttpClient: add put() method; switch invoice submit to PUT docstatus=1 (Frappe v16)
- buildItemDescription() uses specsText + inventory number + serial number
- Integration tests: find Simon Kühn, create real 1337€ invoice, cancel+delete in tearDown
- FRAPPE_GENERIC_ITEM_CODE=SKU002 added to .env.local and bin/test-integration

Pipeline — model cache:
- PhotoUploadHandler: after vision, check DB for existing article with same modelNumber
- On match: copy ebayTitle/ebayDescription/specsText/attributes, skip specs+JSON+eBay steps
- DraftArticleHandler: apply model_match data and mark job complete directly
- ArticleRepository: findCompletedByModelNumber() query

Pipeline — specs by article type:
- SpecsResearchAgent: accept attributeFields list, format as bullet list in {{fields}} var
- SpecsResearchHandler: derive attribute names from ArticleType, pass to agent
- SpecsResearchMessage: add attributeFields param
- Prompt migration: replace hardcoded laptop spec list with {{fields}} placeholder

Article:
- specsText field (nullable text column + migration)
- stock field visible on index and editable in CRUD form
- addAttributeValue()/removeAttributeValue() adder-remover pair for Symfony form binding
- AttributeValue::getArticle() getter
- AttributeValueFormType: detect required attributes from ArticleType assignments, set required=true
- ManualIngestType: add stock/quantity field (default 1, min 1)

Users / ACL:
- PermissionVoter: define named permission constants + allPermissions()
- User: getGrantedPermissions()/setGrantedPermissions() helpers
- UserCrudController: permissions checkbox group on edit form

UI / assets:
- public/css/admin/custom.css: red asterisk for required fields
- DashboardController: register custom CSS

Infra:
- PipelineJobFailureListener: mark job failed (with real error) when Messenger exhausts retries
- doctrine.yaml: exclude app.inventory_seq from schema diff
- ErpAdapterInterface: add findExistingCustomer()

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 16:42:15 +00:00
5b2a200fc2 feat: specs research agent reports corrected model number
When Tavily search results reveal that the OCR'd model number has a
character error, the specs_research prompt asks the LLM to output a
CORRECTED_MODEL_NUMBER line. The agent parses it out, stores it in the
job output, and DraftArticleHandler applies it to the article in
preference to the raw vision value.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 11:00:41 +00:00
cfb5cc4ad0 feat: replace Mistral web_search with Tavily for specs research
- Add WebSearchInterface + TavilyWebSearch (POST /search, max 5 results)
- SpecsResearchAgent now fetches search results first, injects them as
  {{searchResults}} context into the prompt, then calls plain generate()
  — no dependency on model-specific web_search tool support
- Update specs_research prompt template (PHP default + DB migration) to
  use the new {{searchResults}} variable
- Wire TAVILY_API_KEY env var; register TavilyWebSearch in services.yaml

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 08:35:52 +00:00
a38fe7e72d fix: use web search in SpecsResearchAgent to prevent spec hallucination
The agent was calling generate() — pure model memory — which caused Mistral
to hallucinate specs for older devices (e.g. i5-1135G7 instead of i3-3120M).
generateWithWebSearch() is now used so Mistral queries live sources.

OllamaClientInterface gains generateWithWebSearch(); OllamaClient falls back
to generate() since Ollama has no built-in search tool.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 07:28:21 +00:00
49e36a0a06 feat: editable AI prompt templates and articleType context in specs research
All agent prompts are now stored in app.prompt_templates (migration 20260519000000)
and editable by admins via the new AI Prompts CRUD page. If no DB entry exists
for a key the hardcoded default is used automatically as fallback.

PromptTemplateService renders templates with {{variable}} substitution.
All four agents (SpecsResearch, JsonCoding, EbayText, OllamaVision) use the service.

SpecsResearchAgent now receives the articleType name (e.g. "Laptop") so the
specs prompt is scoped to the correct device category instead of being generic.
SpecsResearchHandler loads the ArticleType from the repository for this purpose.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 07:19:02 +00:00
fddfd920f5 feat: add Symfony Messenger pipeline with AI agents and handlers
Messages and handlers for the full AI pipeline:
DraftArticle → Validation → SpecsResearch → PhotoUpload → EbayText →
JsonCoding → PublishToChannel / DeactivateListingMessage / TrackingPush /
UpdateStockOnChannels / OrderReceived.

OllamaClient and OllamaClientInterface provide the base LLM backend.
AI agents (EbayTextAgent, JsonCodingAgent, OllamaVisionAgent,
SpecsResearchAgent) wrap the client with task-specific prompts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 22:43:47 +00:00