3 changed files with 22 additions and 3 deletions
+1
View File
@@ -21,6 +21,7 @@ TOOL DISCIPLINE:
- search_email_history: only for a verified customer asking about their own past emails (quotes, previous inquiries, "I emailed you before"). Never use another person's email; the tool is scoped to the verified identity. - search_email_history: only for a verified customer asking about their own past emails (quotes, previous inquiries, "I emailed you before"). Never use another person's email; the tool is scoped to the verified identity.
- handoff_to_human: call when the customer explicitly asks for a human, is angry/complaining, or the request cannot be resolved with the available tools. Use it instead of only saying "I'll transfer you". - handoff_to_human: call when the customer explicitly asks for a human, is angry/complaining, or the request cannot be resolved with the available tools. Use it instead of only saying "I'll transfer you".
- create_opportunity: as soon as company + a contact (name, email or phone) + product need are known, call it — email verification is NOT required for lead creation. Call it exactly once per customer. If it returns created=false, do not create another. If it returns crm_unavailable, tell the customer the team will follow up and do not retry immediately. NEVER use the words CRM or opportunity in a customer reply (say 'your request' / 'your inquiry' instead), never mention opportunity IDs, internal records, assigned users, or tool results, and never quote an opportunity name/reference. Only claim the request was recorded/registered if the tool actually returned created=true or an existing opportunity; never promise it without calling the tool. - create_opportunity: as soon as company + a contact (name, email or phone) + product need are known, call it — email verification is NOT required for lead creation. Call it exactly once per customer. If it returns created=false, do not create another. If it returns crm_unavailable, tell the customer the team will follow up and do not retry immediately. NEVER use the words CRM or opportunity in a customer reply (say 'your request' / 'your inquiry' instead), never mention opportunity IDs, internal records, assigned users, or tool results, and never quote an opportunity name/reference. Only claim the request was recorded/registered if the tool actually returned created=true or an existing opportunity; never promise it without calling the tool.
- CITATIONS / dropshipping: when the customer asks about dropshipping (dropshipping registration, orders, payment, shipment or returns), prefer the https://dropshipping.yehwang.com/faq/* URLs that appear in the search_kb source_urls. Do NOT replace them with similar www.yehwang.com pages; only fall back to www.yehwang.com when no dropshipping source is available. Cite the URL that actually supports the answer.
VERIFICATION (important): VERIFICATION (important):
- Order lookup requires a verified customer. Opportunity creation does NOT require verification (company + contact + need is enough). - Order lookup requires a verified customer. Opportunity creation does NOT require verification (company + contact + need is enough).
+9 -3
View File
@@ -421,7 +421,8 @@ function createTools(cfg, deps = {}) {
const cmd = { const cmd = {
keyword: rpcQuery, keyword: rpcQuery,
page: 1, page: 1,
pageSize: limit, // 多取候选,下面按库存排序后再截断到 limit,避免缺货商品占满前几条
pageSize: limit * 4,
languageId: profile.languageId, languageId: profile.languageId,
tenantId: profile.tenantId, tenantId: profile.tenantId,
currencyCode: profile.currencyCode || '', currencyCode: profile.currencyCode || '',
@@ -439,7 +440,6 @@ function createTools(cfg, deps = {}) {
const list = Array.isArray(paging) ? paging : (paging.data || paging.list || []); const list = Array.isArray(paging) ? paging : (paging.data || paging.list || []);
total = result.total != null ? result.total : (paging.total != null ? paging.total : null); total = result.total != null ? result.total : (paging.total != null ? paging.total : null);
items = (Array.isArray(list) ? list : []) items = (Array.isArray(list) ? list : [])
.slice(0, limit)
.map((p) => { .map((p) => {
const name = p.spuName || p.name || p.title || null; const name = p.spuName || p.name || p.title || null;
const sku = p.sku || p.model || (Array.isArray(p.skus) && p.skus[0] ? p.skus[0].productId : null); const sku = p.sku || p.model || (Array.isArray(p.skus) && p.skus[0] ? p.skus[0].productId : null);
@@ -458,7 +458,13 @@ function createTools(cfg, deps = {}) {
mark_price: p.markPriceWithCurrency || null, mark_price: p.markPriceWithCurrency || null,
}; };
}) })
.filter((p) => p.name); .filter((p) => p.name)
// 有库存优先:stock>0 → 0,未知 → 1,缺货 → 2;sort 稳定,保留 RPC 原顺序
.sort((a, b) => {
const rank = (p) => (p.stock > 0 ? 0 : p.stock === null ? 1 : 2);
return rank(a) - rank(b);
})
.slice(0, limit);
} catch (err) { } catch (err) {
catalogError = err.message; catalogError = err.message;
} }
+12
View File
@@ -0,0 +1,12 @@
'use strict';
const test = require('node:test');
const assert = require('node:assert/strict');
const { SYSTEM_PROMPT, buildSystemPrompt } = require('../src/prompts');
test('prompt: dropshipping answers prefer dropshipping source urls', () => {
assert.match(SYSTEM_PROMPT, /dropshipping\.yehwang\.com\/faq\//);
assert.match(SYSTEM_PROMPT, /Do NOT replace them with similar www\.yehwang\.com pages/i);
const built = buildSystemPrompt({ verified: false, site: 'www', channel: 'livechat' });
assert.match(built, /dropshipping\.yehwang\.com\/faq\//);
});