Supplier Bot — Interface Contracts

Updated Mar 20 · D1 → D2 → D3 → D2b pipeline
pipeline/context-builder.js · D2+D3 BUILT · D1 BLOCKED · D2b NEXT
D1: chatServer Wire BLOCKED
chatserver-client.js · run-live.js

Send API

sendFirstMessage(productUrl, content) → { taskId, conversationId } sendFollowUp(conversationId, content) → { taskId }

Poll & Read

waitForReply(taskId, timeoutMs) → 'complete' | 'timeout' getNewMessages(convId, after) → [{ content, timestamp, sender }]

Supplier Profile

{ supplierId, storeName, productUrl, ← NEW archetype, platform }
Nudge: no reply after maxWait → send 1 follow-up, wait again. Still silent → no_reply.
result
D2: Outcome Schema BUILT
extractOutcome(result, goals)

Outcome Object

{ supplierId, supplierName, product: string, archetype:string, status: 'completed'|'no_reply' |'rejected'|'wechat_redirect' |'ai_bot_only', turnsCompleted: number, extracted: { [goalId]: { value: string, confidence: 'high' |'medium'|'low', turn: number } }, goalsCompleted: string[], goalsRemaining: string[], freeformNotes: string }
Goal-agnostic: extracted keyed by goal ID from goal-types.json. Works with any goal set.
LLM call: lightweight post-conversation extraction. Per-turn upgrade path later.
outcomes[]
D3: Comparison BUILT
summarizeProgress(outcomes[])

Summary Object

{ total, responded, noReply, rejected, wechat, dims: { [field]: { confirmed: number, values: [{ supplier, supplierId, value, confidence }] } }, missingAcrossAll: string[], comparisonTable: [{ supplierId, name, status, [field]: string|null, goalsCompleted, goalsTotal }], markdown: string }
Pure function. No LLM. Reads whatever goals appear in outcomes and aggregates. Goal changes → zero code changes.
JSON
+
Markdown
+
HTML
Markdown is WA-pasteable. HTML extends report template.
summary
D2b: Context Injection NEXT
buildInjection(summary, suppId)

Output → {{CONTEXT}}

## Progress (7 of 20) Responded: 5 | No reply: 1 Confirmed: - MOQ: 300–1000 pcs (5) - Price: $2.10–$3.50 (best: $2.10) - Lead time: 10–25 days (4) Missing across all: - Sample terms (1/5) - Certification (0/5)
Brain replaces THIS layer
Brain calls summarizeProgress() for data, then produces its own string for {{CONTEXT}}:
PRIORITY: Push for price + sample.
Skip packing — 4 others confirmed.
Constraints: max ~500 tokens. Excludes current supplier. Factual only — no strategy.
Handoff: Team replaces buildInjection(). D2+D3 stay. | Round model: Round 1 (no context, 3–6h cutoff) → Extract+Compare → Round 2+ (context injected, targeted follow-up). | D1 D2 D3 D2b Brain
Prepared by Eric San · Updated 20 Mar 2026