n8n-nodes-tembory 1.1.5 → 1.1.6
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.
|
@@ -399,275 +399,6 @@ const safeParseToolPayload = (value) => {
|
|
|
399
399
|
return text;
|
|
400
400
|
}
|
|
401
401
|
};
|
|
402
|
-
const parseNestedToolPayload = (value, depth = 0) => {
|
|
403
|
-
if (depth > 8)
|
|
404
|
-
return value;
|
|
405
|
-
if (typeof value === 'string') {
|
|
406
|
-
const text = value.trim();
|
|
407
|
-
if (!text)
|
|
408
|
-
return '';
|
|
409
|
-
if (!/^[\[{]/.test(text))
|
|
410
|
-
return value;
|
|
411
|
-
try {
|
|
412
|
-
return parseNestedToolPayload(JSON.parse(text), depth + 1);
|
|
413
|
-
}
|
|
414
|
-
catch {
|
|
415
|
-
return value;
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
if (Array.isArray(value))
|
|
419
|
-
return value.map((item) => parseNestedToolPayload(item, depth + 1));
|
|
420
|
-
if (!value || typeof value !== 'object')
|
|
421
|
-
return value;
|
|
422
|
-
const out = {};
|
|
423
|
-
for (const [key, item] of Object.entries(value))
|
|
424
|
-
out[key] = parseNestedToolPayload(item, depth + 1);
|
|
425
|
-
return out;
|
|
426
|
-
};
|
|
427
|
-
const collectObjectsDeep = (value, out = [], seen = new Set()) => {
|
|
428
|
-
if (!value || typeof value !== 'object' || seen.has(value))
|
|
429
|
-
return out;
|
|
430
|
-
seen.add(value);
|
|
431
|
-
if (!Array.isArray(value))
|
|
432
|
-
out.push(value);
|
|
433
|
-
for (const item of Array.isArray(value) ? value : Object.values(value))
|
|
434
|
-
collectObjectsDeep(item, out, seen);
|
|
435
|
-
return out;
|
|
436
|
-
};
|
|
437
|
-
const compactObject = (value) => {
|
|
438
|
-
if (Array.isArray(value)) {
|
|
439
|
-
const arr = value.map(compactObject).filter((item) => item !== undefined);
|
|
440
|
-
return arr.length ? arr : undefined;
|
|
441
|
-
}
|
|
442
|
-
if (!value || typeof value !== 'object')
|
|
443
|
-
return value === '' || value === null || value === undefined ? undefined : value;
|
|
444
|
-
const out = {};
|
|
445
|
-
for (const [key, item] of Object.entries(value)) {
|
|
446
|
-
const cleaned = compactObject(item);
|
|
447
|
-
if (cleaned !== undefined)
|
|
448
|
-
out[key] = cleaned;
|
|
449
|
-
}
|
|
450
|
-
return Object.keys(out).length ? out : undefined;
|
|
451
|
-
};
|
|
452
|
-
const normalizeFieldKey = (value = '') => String(value || '').toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
453
|
-
const hasFieldKey = (key, candidates) => candidates.map(normalizeFieldKey).includes(normalizeFieldKey(key));
|
|
454
|
-
const findFieldDeep = (value, keys) => {
|
|
455
|
-
const objects = collectObjectsDeep(value);
|
|
456
|
-
for (const object of objects) {
|
|
457
|
-
for (const [key, item] of Object.entries(object)) {
|
|
458
|
-
if (hasFieldKey(key, keys) && item !== undefined && item !== null && item !== '')
|
|
459
|
-
return item;
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
return undefined;
|
|
463
|
-
};
|
|
464
|
-
const readPath = (value, path) => {
|
|
465
|
-
let current = value;
|
|
466
|
-
for (const segment of path) {
|
|
467
|
-
if (!current || typeof current !== 'object')
|
|
468
|
-
return undefined;
|
|
469
|
-
current = current[segment];
|
|
470
|
-
}
|
|
471
|
-
return current;
|
|
472
|
-
};
|
|
473
|
-
const firstPath = (roots, paths) => {
|
|
474
|
-
for (const root of roots) {
|
|
475
|
-
for (const path of paths) {
|
|
476
|
-
const value = readPath(root, path);
|
|
477
|
-
if (value !== undefined && value !== null && value !== '')
|
|
478
|
-
return value;
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
return undefined;
|
|
482
|
-
};
|
|
483
|
-
const numberFrom = (value) => {
|
|
484
|
-
if (value === undefined || value === null || value === '')
|
|
485
|
-
return undefined;
|
|
486
|
-
const match = String(value).match(/-?\d+(?:[.,]\d+)?/);
|
|
487
|
-
if (!match)
|
|
488
|
-
return undefined;
|
|
489
|
-
const parsed = Number(match[0].replace(',', '.'));
|
|
490
|
-
return Number.isFinite(parsed) ? parsed : undefined;
|
|
491
|
-
};
|
|
492
|
-
const integerFrom = (value) => {
|
|
493
|
-
const parsed = numberFrom(value);
|
|
494
|
-
return parsed === undefined ? undefined : Math.trunc(parsed);
|
|
495
|
-
};
|
|
496
|
-
const normalizeTimeValue = (value) => {
|
|
497
|
-
const text = String(value || '').trim().toLowerCase();
|
|
498
|
-
const match = /^(\d{1,2})(?:(?::|h)(\d{0,2}))?$/.exec(text);
|
|
499
|
-
if (!match)
|
|
500
|
-
return '';
|
|
501
|
-
const hour = Number(match[1]);
|
|
502
|
-
const minute = match[2] === '' || match[2] === undefined ? 0 : Number(match[2]);
|
|
503
|
-
if (hour < 0 || hour > 23 || minute < 0 || minute > 59)
|
|
504
|
-
return '';
|
|
505
|
-
return `${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}`;
|
|
506
|
-
};
|
|
507
|
-
const isoDateFromParts = (day, month, year, referenceDates = []) => {
|
|
508
|
-
const dd = String(day || '').padStart(2, '0');
|
|
509
|
-
const mm = String(month || '').padStart(2, '0');
|
|
510
|
-
let yyyy = String(year || '');
|
|
511
|
-
if (!yyyy) {
|
|
512
|
-
const matched = (referenceDates || []).find((date) => String(date || '').slice(5, 10) === `${mm}-${dd}`);
|
|
513
|
-
yyyy = matched ? String(matched).slice(0, 4) : String(new Date().getFullYear());
|
|
514
|
-
}
|
|
515
|
-
if (yyyy.length === 2)
|
|
516
|
-
yyyy = `20${yyyy}`;
|
|
517
|
-
return /^\d{4}$/.test(yyyy) && /^\d{2}$/.test(mm) && /^\d{2}$/.test(dd) ? `${yyyy}-${mm}-${dd}` : '';
|
|
518
|
-
};
|
|
519
|
-
const bookingToolName = (name = '') => String(name || '').toLowerCase();
|
|
520
|
-
const serviceNameFromPageContent = (value) => {
|
|
521
|
-
const content = String(value || '').trim();
|
|
522
|
-
if (!content)
|
|
523
|
-
return '';
|
|
524
|
-
return content.split(/\r?\n/).map((line) => line.trim()).find(Boolean) || '';
|
|
525
|
-
};
|
|
526
|
-
const extractAvailabilitySlots = (parsedResult) => {
|
|
527
|
-
const slots = [];
|
|
528
|
-
const roots = Array.isArray(parsedResult) ? parsedResult : [parsedResult];
|
|
529
|
-
for (const root of roots) {
|
|
530
|
-
if (!root || typeof root !== 'object')
|
|
531
|
-
continue;
|
|
532
|
-
const availability = Array.isArray(root.disponibilidade) ? root.disponibilidade : [];
|
|
533
|
-
for (const item of availability) {
|
|
534
|
-
const date = item.dataDisponivel || item.date || item.data || '';
|
|
535
|
-
const providers = Array.isArray(item.providers) ? item.providers : [];
|
|
536
|
-
for (const provider of providers) {
|
|
537
|
-
const providerId = integerFrom(provider.provider_id ?? provider.providerId ?? provider.id);
|
|
538
|
-
const providerName = provider.provider_name || provider.providerName || provider.name || '';
|
|
539
|
-
const horarios = Array.isArray(provider.horarios) ? provider.horarios : [];
|
|
540
|
-
for (const horario of horarios) {
|
|
541
|
-
const time = normalizeTimeValue(horario);
|
|
542
|
-
if (date && time)
|
|
543
|
-
slots.push(compactObject({ date, time, providerId, providerName }));
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
return slots.filter(Boolean);
|
|
549
|
-
};
|
|
550
|
-
const extractToolBookingFacts = (toolName = '', input = '', rawResult = '') => {
|
|
551
|
-
const name = bookingToolName(toolName);
|
|
552
|
-
const inputObj = parseNestedToolPayload(safeParseToolPayload(input));
|
|
553
|
-
const parsedResult = parseNestedToolPayload(safeParseToolPayload(rawResult));
|
|
554
|
-
const roots = Array.isArray(parsedResult) ? parsedResult : [parsedResult];
|
|
555
|
-
const objects = collectObjectsDeep(parsedResult);
|
|
556
|
-
const facts = { source_tool: toolName };
|
|
557
|
-
if (/check[_-]?availabilities|disponibilidade/i.test(name)) {
|
|
558
|
-
facts.kind = 'availability';
|
|
559
|
-
facts.locationId = integerFrom(firstPath(roots, [['locationId'], ['location_id']]) ?? findFieldDeep(parsedResult, ['locationId', 'location_id']));
|
|
560
|
-
facts.locationName = inputObj && typeof inputObj === 'object' ? inputObj.location_name || inputObj.locationName : undefined;
|
|
561
|
-
facts.serviceName = firstPath(roots, [['especialidade'], ['serviceName'], ['service_name']]) || (inputObj && typeof inputObj === 'object' ? inputObj.service_name || inputObj.serviceName : undefined);
|
|
562
|
-
facts.serviceId = integerFrom(firstPath(roots, [['services', 'id'], ['service', 'id'], ['serviceId'], ['service_id']]) ?? findFieldDeep(parsedResult, ['serviceId', 'service_id']));
|
|
563
|
-
facts.durationMinutes = integerFrom(firstPath(roots, [['services', 'duration'], ['duration'], ['durationMinutes']]) ?? findFieldDeep(parsedResult, ['duration', 'durationMinutes']));
|
|
564
|
-
facts.price = firstPath(roots, [['services', 'price'], ['price']]) ?? findFieldDeep(parsedResult, ['price', 'price_num']);
|
|
565
|
-
facts.providerId = integerFrom(firstPath(roots, [['provider', 'id'], ['providerId'], ['provider_id']]) ?? findFieldDeep(parsedResult, ['providerId', 'provider_id']));
|
|
566
|
-
facts.availability_slots = extractAvailabilitySlots(parsedResult).slice(0, 80);
|
|
567
|
-
}
|
|
568
|
-
else if (/services?|veterinarios?/i.test(name)) {
|
|
569
|
-
facts.kind = /veterinarios?/i.test(name) ? 'provider_service' : 'service';
|
|
570
|
-
facts.serviceId = integerFrom(firstPath(roots, [['metadata', 'metadata', 'service_id'], ['metadata', 'service_id'], ['service_id'], ['serviceId']]) ?? findFieldDeep(parsedResult, ['service_id', 'serviceId']));
|
|
571
|
-
facts.serviceName = firstPath(roots, [['pageContent']]) || (objects.map((object) => serviceNameFromPageContent(object.pageContent)).find(Boolean));
|
|
572
|
-
facts.serviceName = serviceNameFromPageContent(facts.serviceName || '');
|
|
573
|
-
facts.locationId = integerFrom(firstPath(roots, [['metadata', 'metadata', 'location_id'], ['metadata', 'location_id'], ['locationId'], ['local']]) ?? findFieldDeep(parsedResult, ['location_id', 'locationId', 'local']));
|
|
574
|
-
facts.providerId = integerFrom(firstPath(roots, [['metadata', 'metadata', 'provider_id'], ['metadata', 'provider_id'], ['provider_id'], ['providerId']]) ?? findFieldDeep(parsedResult, ['provider_id', 'providerId']));
|
|
575
|
-
facts.price = firstPath(roots, [['metadata', 'metadata', 'price_num'], ['metadata', 'price_num'], ['price']]) ?? findFieldDeep(parsedResult, ['price_num', 'price']);
|
|
576
|
-
facts.durationMinutes = integerFrom(firstPath(roots, [['metadata', 'metadata', 'duration'], ['metadata', 'duration'], ['duration']]) ?? findFieldDeep(parsedResult, ['duration']));
|
|
577
|
-
}
|
|
578
|
-
else if (/anclivepa.*customer.*upsert|customer.*upsert/i.test(name)) {
|
|
579
|
-
facts.kind = 'booking_customer';
|
|
580
|
-
facts.customerId = integerFrom(firstPath(roots, [['customerId'], ['customer_id']]) ?? findFieldDeep(parsedResult, ['customerId', 'customer_id']));
|
|
581
|
-
facts.petName = firstPath(roots, [['petChosen'], ['petName'], ['pet_name']]) || (inputObj && typeof inputObj === 'object' ? inputObj.petName || inputObj.pet_name : undefined);
|
|
582
|
-
facts.readyForBooking = Boolean(firstPath(roots, [['readyForBooking']]) ?? findFieldDeep(parsedResult, ['readyForBooking']));
|
|
583
|
-
}
|
|
584
|
-
const compacted = compactObject(facts);
|
|
585
|
-
return compacted && Object.keys(compacted).length > 2 ? compacted : undefined;
|
|
586
|
-
};
|
|
587
|
-
const extractBookingSelectionFromMessages = (recentMessages = [], referenceDates = []) => {
|
|
588
|
-
const ordered = [...(recentMessages || [])].reverse();
|
|
589
|
-
for (const msg of ordered) {
|
|
590
|
-
const text = String(msg.content || '');
|
|
591
|
-
const dateTime = /(\d{1,2})[/-](\d{1,2})(?:[/-](\d{2,4}))?[\s\S]{0,160}?(?:às|as|hor[aá]rio)\s*(\d{1,2})(?:(?::|h)(\d{2}))?/i.exec(text);
|
|
592
|
-
if (dateTime) {
|
|
593
|
-
return compactObject({
|
|
594
|
-
date: isoDateFromParts(dateTime[1], dateTime[2], dateTime[3], referenceDates),
|
|
595
|
-
time: normalizeTimeValue(`${dateTime[4]}:${dateTime[5] || '00'}`),
|
|
596
|
-
source: 'recent_message',
|
|
597
|
-
}) || {};
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
const dateMsg = ordered.find((msg) => /(\d{1,2})[/-](\d{1,2})(?:[/-](\d{2,4}))?/.test(String(msg.content || '')));
|
|
601
|
-
const timeMsg = ordered.find((msg) => /^(?:\s*(?:às|as)\s*)?\d{1,2}(?:(?::|h)\d{0,2})?\s*$/i.test(String(msg.content || '')));
|
|
602
|
-
const dateMatch = dateMsg ? /(\d{1,2})[/-](\d{1,2})(?:[/-](\d{2,4}))?/.exec(String(dateMsg.content || '')) : null;
|
|
603
|
-
return compactObject({
|
|
604
|
-
date: dateMatch ? isoDateFromParts(dateMatch[1], dateMatch[2], dateMatch[3], referenceDates) : undefined,
|
|
605
|
-
time: timeMsg ? normalizeTimeValue(timeMsg.content) : undefined,
|
|
606
|
-
source: dateMatch || timeMsg ? 'recent_message_partial' : undefined,
|
|
607
|
-
}) || {};
|
|
608
|
-
};
|
|
609
|
-
const addMinutesToSlot = (date, time, minutes = 60) => {
|
|
610
|
-
if (!date || !time)
|
|
611
|
-
return '';
|
|
612
|
-
const start = new Date(`${date}T${time}:00Z`);
|
|
613
|
-
if (!Number.isFinite(start.getTime()))
|
|
614
|
-
return '';
|
|
615
|
-
const end = new Date(start.getTime() + (Number(minutes) || 60) * 60000);
|
|
616
|
-
return `${end.toISOString().slice(0, 10)} ${end.toISOString().slice(11, 19)}`;
|
|
617
|
-
};
|
|
618
|
-
const deriveBookingState = (toolHistory = [], recentMessages = []) => {
|
|
619
|
-
const facts = (toolHistory || []).map((tool) => tool.booking_facts || extractToolBookingFacts(tool.name, tool.input, tool.result)).filter(Boolean);
|
|
620
|
-
if (!facts.length)
|
|
621
|
-
return undefined;
|
|
622
|
-
const latest = (predicate) => [...facts].reverse().find(predicate) || {};
|
|
623
|
-
const availability = latest((fact) => Array.isArray(fact.availability_slots) && fact.availability_slots.length);
|
|
624
|
-
const service = latest((fact) => fact.serviceId);
|
|
625
|
-
const customer = latest((fact) => fact.kind === 'booking_customer' && fact.customerId);
|
|
626
|
-
const slots = availability.availability_slots || [];
|
|
627
|
-
const referenceDates = Array.from(new Set(slots.map((slot) => slot.date).filter(Boolean)));
|
|
628
|
-
const selection = extractBookingSelectionFromMessages(recentMessages, referenceDates);
|
|
629
|
-
const selectedSlot = slots.find((slot) => slot.date === selection.date && slot.time === selection.time) || {};
|
|
630
|
-
const uniqueProviderIds = Array.from(new Set(slots.map((slot) => slot.providerId).filter(Boolean)));
|
|
631
|
-
const durationMinutes = availability.durationMinutes || service.durationMinutes || 60;
|
|
632
|
-
const providerId = selectedSlot.providerId || (uniqueProviderIds.length === 1 ? uniqueProviderIds[0] : availability.providerId || service.providerId);
|
|
633
|
-
const serviceId = availability.serviceId || service.serviceId;
|
|
634
|
-
const locationId = availability.locationId || service.locationId;
|
|
635
|
-
const customerId = customer.customerId;
|
|
636
|
-
const start = selection.date && selection.time ? `${selection.date} ${selection.time}:00` : undefined;
|
|
637
|
-
const end = start ? addMinutesToSlot(selection.date, selection.time, durationMinutes) : undefined;
|
|
638
|
-
const bookingCandidate = compactObject({
|
|
639
|
-
start,
|
|
640
|
-
end,
|
|
641
|
-
date: selection.date,
|
|
642
|
-
time: selection.time,
|
|
643
|
-
providerId,
|
|
644
|
-
providerName: selectedSlot.providerName,
|
|
645
|
-
serviceId,
|
|
646
|
-
serviceName: availability.serviceName || service.serviceName,
|
|
647
|
-
locationId,
|
|
648
|
-
locationName: availability.locationName,
|
|
649
|
-
customerId,
|
|
650
|
-
petName: customer.petName,
|
|
651
|
-
durationMinutes,
|
|
652
|
-
price: availability.price || service.price,
|
|
653
|
-
source: 'derived_from_tool_history',
|
|
654
|
-
}) || {};
|
|
655
|
-
const required = ['providerId', 'serviceId', 'locationId', 'customerId', 'date', 'time'];
|
|
656
|
-
const missing = required.filter((key) => bookingCandidate[key] === undefined || bookingCandidate[key] === null || bookingCandidate[key] === '');
|
|
657
|
-
const warnings = [];
|
|
658
|
-
if (bookingCandidate.providerId && bookingCandidate.locationId && String(bookingCandidate.providerId) === String(bookingCandidate.locationId))
|
|
659
|
-
warnings.push('providerId_equals_locationId');
|
|
660
|
-
if (bookingCandidate.serviceId && bookingCandidate.locationId && String(bookingCandidate.serviceId) === String(bookingCandidate.locationId))
|
|
661
|
-
warnings.push('serviceId_equals_locationId');
|
|
662
|
-
return compactObject({
|
|
663
|
-
booking_candidate: bookingCandidate,
|
|
664
|
-
selected_slot: selectedSlot,
|
|
665
|
-
missing,
|
|
666
|
-
warnings,
|
|
667
|
-
available_slot_count: slots.length || undefined,
|
|
668
|
-
source_tools: Array.from(new Set(facts.map((fact) => fact.source_tool).filter(Boolean))),
|
|
669
|
-
});
|
|
670
|
-
};
|
|
671
402
|
const compactToolPayload = (value) => truncate(typeof value === 'string' ? value : safeStringify(value), 900);
|
|
672
403
|
const maybeToolResult = (tool, includeResults = true) => includeResults === false ? undefined : compactToolPayload(safeParseToolPayload(tool === null || tool === void 0 ? void 0 : tool.result));
|
|
673
404
|
const isToolName = (value = '') => /^[A-Za-z_][A-Za-z0-9_.:-]{1,127}$/.test(String(value || ''));
|
|
@@ -707,7 +438,6 @@ const deriveOperationalState = (toolHistory = [], profileFacts = {}, recentMessa
|
|
|
707
438
|
at: tool.at || null,
|
|
708
439
|
input: compactInput,
|
|
709
440
|
result: compactResult,
|
|
710
|
-
booking_facts: tool.booking_facts,
|
|
711
441
|
reason,
|
|
712
442
|
source: tool.source || 'unknown',
|
|
713
443
|
};
|
|
@@ -719,7 +449,6 @@ const deriveOperationalState = (toolHistory = [], profileFacts = {}, recentMessa
|
|
|
719
449
|
reason,
|
|
720
450
|
input: compactInput,
|
|
721
451
|
output: compactResult,
|
|
722
|
-
booking_facts: tool.booking_facts,
|
|
723
452
|
}));
|
|
724
453
|
if (tool.ok === false)
|
|
725
454
|
failedByName[name] = (failedByName[name] || 0) + 1;
|
|
@@ -729,11 +458,9 @@ const deriveOperationalState = (toolHistory = [], profileFacts = {}, recentMessa
|
|
|
729
458
|
const guidance = [
|
|
730
459
|
'Use tool_state and action_ledger as the source of truth for prior tool calls, inputs, outputs, failures and decisions. Domain-specific tool policy must come from the agent prompt, not from memory.',
|
|
731
460
|
];
|
|
732
|
-
const bookingState = deriveBookingState(tools, recentMessages);
|
|
733
461
|
return {
|
|
734
462
|
profile_complete: Boolean(profileFacts && profileFacts.name && profileFacts.company && profileFacts.email && profileFacts.phone),
|
|
735
463
|
last_tool: lastTool ? { name: lastTool.name, ok: lastTool.ok, at: lastTool.at } : null,
|
|
736
|
-
booking_state: bookingState,
|
|
737
464
|
tool_counts: {
|
|
738
465
|
total: tools.length,
|
|
739
466
|
ok: successfulTools.length,
|
|
@@ -753,7 +480,6 @@ const deriveOperationalState = (toolHistory = [], profileFacts = {}, recentMessa
|
|
|
753
480
|
name: successfulTools[successfulTools.length - 1].name,
|
|
754
481
|
at: successfulTools[successfulTools.length - 1].at || null,
|
|
755
482
|
result: maybeToolResult(successfulTools[successfulTools.length - 1], includeResults),
|
|
756
|
-
booking_facts: successfulTools[successfulTools.length - 1].booking_facts,
|
|
757
483
|
} : null,
|
|
758
484
|
},
|
|
759
485
|
blocked_without_context: Array.from(new Set(blockedWithoutContext)),
|
|
@@ -772,7 +498,6 @@ const deriveActionLedger = (toolHistory = [], maxItems = 20, includeResults = tr
|
|
|
772
498
|
reason: truncate(String(tool.reason || tool.decision || tool.why || tool.source || 'recorded tool call'), 260),
|
|
773
499
|
input: compactToolPayload(safeParseToolPayload(tool.input)),
|
|
774
500
|
result: maybeToolResult(tool, includeResults),
|
|
775
|
-
booking_facts: tool.booking_facts,
|
|
776
501
|
at: tool.at || null,
|
|
777
502
|
source: tool.source || 'unknown',
|
|
778
503
|
})), maxItems || 20);
|
|
@@ -877,7 +602,6 @@ const encodeToolCall = (tool, threadId) => `${TOOL_HISTORY_MARKER}${safeStringif
|
|
|
877
602
|
input: tool.input || '',
|
|
878
603
|
ok: tool.ok !== false,
|
|
879
604
|
result: tool.result || '',
|
|
880
|
-
booking_facts: tool.booking_facts,
|
|
881
605
|
at: tool.at || nowIso(),
|
|
882
606
|
source: tool.source || 'n8n',
|
|
883
607
|
thread_id: threadId,
|
|
@@ -897,7 +621,6 @@ const encodeToolLedger = (tools = [], threadId) => {
|
|
|
897
621
|
input: tool.input || '',
|
|
898
622
|
ok: tool.ok !== false,
|
|
899
623
|
result: tool.result || '',
|
|
900
|
-
booking_facts: tool.booking_facts,
|
|
901
624
|
at: tool.at || nowIso(),
|
|
902
625
|
source: tool.source || 'n8n',
|
|
903
626
|
})),
|
|
@@ -924,7 +647,6 @@ const encodeTurnArchive = ({ threadId, messages = [], tools = [], workingMemory
|
|
|
924
647
|
input: tool.input || '',
|
|
925
648
|
ok: tool.ok !== false,
|
|
926
649
|
output: tool.result || '',
|
|
927
|
-
booking_facts: tool.booking_facts,
|
|
928
650
|
at: tool.at || nowIso(),
|
|
929
651
|
source: tool.source || 'n8n',
|
|
930
652
|
})),
|
|
@@ -965,8 +687,7 @@ const parseToolHistoryMarker = (text) => {
|
|
|
965
687
|
name: String(parsed.name),
|
|
966
688
|
input: parsed.input === undefined ? '' : String(parsed.input),
|
|
967
689
|
ok: parsed.ok !== false,
|
|
968
|
-
result:
|
|
969
|
-
booking_facts: parsed.booking_facts || parsed.bookingFacts,
|
|
690
|
+
result: parsed.result === undefined ? '' : String(parsed.result),
|
|
970
691
|
at: parsed.at || nowIso(),
|
|
971
692
|
source: parsed.source || 'tembory_marker',
|
|
972
693
|
};
|
|
@@ -993,8 +714,7 @@ const parseToolLedgerMarker = (text) => {
|
|
|
993
714
|
name: String(tool.name),
|
|
994
715
|
input: tool.input === undefined ? '' : String(tool.input),
|
|
995
716
|
ok: tool.ok !== false,
|
|
996
|
-
result:
|
|
997
|
-
booking_facts: tool.booking_facts || tool.bookingFacts,
|
|
717
|
+
result: tool.result === undefined ? '' : String(tool.result),
|
|
998
718
|
at: tool.at || parsed.generated_at || nowIso(),
|
|
999
719
|
source: tool.source || 'tool_ledger_marker',
|
|
1000
720
|
}));
|
|
@@ -1097,8 +817,7 @@ const toolHistoryFromMemory = (item) => {
|
|
|
1097
817
|
name: factMatch[1],
|
|
1098
818
|
input: truncate((factMatch[2] || '').trim(), 1000),
|
|
1099
819
|
ok: true,
|
|
1100
|
-
result:
|
|
1101
|
-
booking_facts: meta.booking_facts || meta.bookingFacts,
|
|
820
|
+
result: (factMatch[3] || '').trim(),
|
|
1102
821
|
at: meta.at || item.created_at || item.createdAt || nowIso(),
|
|
1103
822
|
source: 'semantic_fact',
|
|
1104
823
|
};
|
|
@@ -1127,8 +846,7 @@ const toolHistoryFromMemory = (item) => {
|
|
|
1127
846
|
name: String(name),
|
|
1128
847
|
input: meta.input === undefined ? '' : String(meta.input),
|
|
1129
848
|
ok: meta.ok !== false,
|
|
1130
|
-
result:
|
|
1131
|
-
booking_facts: meta.booking_facts || meta.bookingFacts,
|
|
849
|
+
result: meta.result === undefined ? String(content || '') : String(meta.result),
|
|
1132
850
|
at: meta.at || item.created_at || item.createdAt || nowIso(),
|
|
1133
851
|
source: meta.source || 'metadata',
|
|
1134
852
|
};
|
|
@@ -1147,8 +865,7 @@ const explicitToolHistoryItemsFromMemory = (item) => {
|
|
|
1147
865
|
name: String(tool.name),
|
|
1148
866
|
input: tool.input === undefined ? '' : String(tool.input),
|
|
1149
867
|
ok: tool.ok !== false,
|
|
1150
|
-
result:
|
|
1151
|
-
booking_facts: tool.booking_facts || tool.bookingFacts,
|
|
868
|
+
result: tool.output === undefined && tool.result === undefined ? '' : String(tool.output ?? tool.result),
|
|
1152
869
|
at: tool.at || archive.generated_at || nowIso(),
|
|
1153
870
|
source: tool.source || 'turn_archive',
|
|
1154
871
|
}));
|
|
@@ -1213,9 +930,9 @@ const canonicalToolInput = (value) => {
|
|
|
1213
930
|
const normalizeToolCall = (tool, sequence = 0, defaults = {}) => {
|
|
1214
931
|
const at = tool.at || defaults.at || nowIso();
|
|
1215
932
|
const input = canonicalToolInput(tool.input);
|
|
1216
|
-
const rawResult = tool.result
|
|
1217
|
-
const result =
|
|
1218
|
-
const
|
|
933
|
+
const rawResult = tool.result !== undefined ? tool.result : tool.output !== undefined ? tool.output : tool.observation !== undefined ? tool.observation : '';
|
|
934
|
+
const result = typeof rawResult === 'string' ? rawResult : safeStringify(rawResult);
|
|
935
|
+
const resultSummary = summarizeToolResult(rawResult);
|
|
1219
936
|
const normalized = {
|
|
1220
937
|
id: tool.id || tool.callId || tool.call_id || '',
|
|
1221
938
|
call_id: tool.id || tool.callId || tool.call_id || '',
|
|
@@ -1229,15 +946,12 @@ const normalizeToolCall = (tool, sequence = 0, defaults = {}) => {
|
|
|
1229
946
|
normalized_args: input,
|
|
1230
947
|
ok: tool.ok !== false,
|
|
1231
948
|
result,
|
|
1232
|
-
result_summary:
|
|
1233
|
-
booking_facts: bookingFacts,
|
|
949
|
+
result_summary: resultSummary,
|
|
1234
950
|
at,
|
|
1235
951
|
timestamp: at,
|
|
1236
952
|
source: tool.source || defaults.source || 'n8n',
|
|
1237
953
|
status: tool.ok === false ? 'failed' : 'ok',
|
|
1238
954
|
};
|
|
1239
|
-
if (!normalized.booking_facts)
|
|
1240
|
-
delete normalized.booking_facts;
|
|
1241
955
|
if (!normalized.id)
|
|
1242
956
|
normalized.id = makeToolEventId(normalized, normalized.sequence);
|
|
1243
957
|
if (!normalized.call_id)
|
|
@@ -1315,11 +1029,8 @@ const extractToolCallsFromMessages = (messages = []) => {
|
|
|
1315
1029
|
const existing = id ? toolCallById.get(String(id)) : null;
|
|
1316
1030
|
if (existing) {
|
|
1317
1031
|
const rawContent = messageContentOf(message);
|
|
1318
|
-
existing.result =
|
|
1319
|
-
existing.result_summary =
|
|
1320
|
-
existing.booking_facts = extractToolBookingFacts(existing.name, existing.input, rawContent) || existing.booking_facts;
|
|
1321
|
-
if (!existing.booking_facts)
|
|
1322
|
-
delete existing.booking_facts;
|
|
1032
|
+
existing.result = rawContent;
|
|
1033
|
+
existing.result_summary = summarizeToolResult(rawContent);
|
|
1323
1034
|
existing.ok = true;
|
|
1324
1035
|
existing.status = 'ok';
|
|
1325
1036
|
existing.result_hash = stableHash(existing.result || '');
|
|
@@ -1357,7 +1068,7 @@ const extractToolCallsFromText = (text, at = nowIso()) => {
|
|
|
1357
1068
|
name,
|
|
1358
1069
|
input: match[2].trim(),
|
|
1359
1070
|
ok: true,
|
|
1360
|
-
result:
|
|
1071
|
+
result: match[3].trim(),
|
|
1361
1072
|
at,
|
|
1362
1073
|
source: 'used_tools_text',
|
|
1363
1074
|
}, calls.length + 1));
|
|
@@ -1377,7 +1088,7 @@ const extractToolCalls = (outputValues = {}) => {
|
|
|
1377
1088
|
name: String(name),
|
|
1378
1089
|
input: input === undefined ? '' : (typeof input === 'string' ? input : stableStringify(input)),
|
|
1379
1090
|
ok,
|
|
1380
|
-
result
|
|
1091
|
+
result,
|
|
1381
1092
|
at,
|
|
1382
1093
|
source: meta.source || 'intermediate_steps',
|
|
1383
1094
|
}, calls.length + 1, { at }));
|
|
@@ -2320,7 +2031,6 @@ const compactToolHistoryForAgent = (toolHistory = [], maxItems = 6, includeResul
|
|
|
2320
2031
|
reason: truncate(String(tool.reason || tool.decision || tool.why || tool.source || 'recorded tool call'), 140),
|
|
2321
2032
|
input: truncate(String(tool.input || ''), 140) || undefined,
|
|
2322
2033
|
result: includeResults ? compactToolResult(tool.result, 240) : undefined,
|
|
2323
|
-
booking_facts: tool.booking_facts,
|
|
2324
2034
|
}));
|
|
2325
2035
|
const cleanContextValue = (value) => {
|
|
2326
2036
|
if (Array.isArray(value)) {
|
|
@@ -2377,7 +2087,6 @@ const compactOperationalStateForAgent = (state = {}) => {
|
|
|
2377
2087
|
const toolState = state.tool_state || {};
|
|
2378
2088
|
return {
|
|
2379
2089
|
last_tool: state.last_tool || null,
|
|
2380
|
-
booking_state: state.booking_state,
|
|
2381
2090
|
tool_counts: {
|
|
2382
2091
|
total: counts.total || 0,
|
|
2383
2092
|
ok: counts.ok || 0,
|
|
@@ -2406,7 +2115,6 @@ const compactActionLedgerForAgent = (ledger = [], maxItems = 6, includeResults =
|
|
|
2406
2115
|
reason: item.reason,
|
|
2407
2116
|
input: item.input,
|
|
2408
2117
|
result: includeResults ? compactToolResult(item.result, 180) : undefined,
|
|
2409
|
-
booking_facts: item.booking_facts,
|
|
2410
2118
|
}));
|
|
2411
2119
|
const compactEntityTimelineForAgent = (timeline = [], maxItems = 8) => pruneByLimit(timeline || [], maxItems).map((item) => cleanContextValue({
|
|
2412
2120
|
entity: item.entity || item.source || item.name,
|
|
@@ -2715,7 +2423,6 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
|
|
|
2715
2423
|
const vectorFacts = sectionValue('summary');
|
|
2716
2424
|
const slmSummary = sectionValue('connected_model_summary') || sectionValue('active_summary');
|
|
2717
2425
|
const directive = sectionValue('action_directive');
|
|
2718
|
-
const bookingState = (operationalState || {}).booking_state;
|
|
2719
2426
|
const inferredIntent = deriveUserIntentObservation({ query, workingMemory, decisionState, recentMessages });
|
|
2720
2427
|
const minimalState = cleanContextValue({
|
|
2721
2428
|
next_expected_action: directive ? undefined : workingMemory.next_expected_action,
|
|
@@ -2741,7 +2448,6 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
|
|
|
2741
2448
|
slm: hasToolLedger ? undefined : slmSummary,
|
|
2742
2449
|
},
|
|
2743
2450
|
state: minimalState,
|
|
2744
|
-
booking: bookingState,
|
|
2745
2451
|
profile: sectionValue('profile_facts'),
|
|
2746
2452
|
tools: compactToolLedger,
|
|
2747
2453
|
});
|
|
@@ -3467,7 +3173,6 @@ class TemboryMemory {
|
|
|
3467
3173
|
input: tool.input,
|
|
3468
3174
|
ok: tool.ok,
|
|
3469
3175
|
result: tool.result,
|
|
3470
|
-
booking_facts: tool.booking_facts,
|
|
3471
3176
|
at: tool.at,
|
|
3472
3177
|
source: tool.source || 'tembory_transcript',
|
|
3473
3178
|
thread_id: threadId,
|
|
@@ -4195,7 +3900,6 @@ class TemboryMemory {
|
|
|
4195
3900
|
dedupe_key: tool.dedupe_key || toolEventKey(tool),
|
|
4196
3901
|
result: adv.includeToolResults === false ? undefined : tool.result,
|
|
4197
3902
|
result_summary: adv.includeToolResults === false ? undefined : (tool.result_summary || tool.result),
|
|
4198
|
-
booking_facts: tool.booking_facts,
|
|
4199
3903
|
})),
|
|
4200
3904
|
},
|
|
4201
3905
|
diagnostics,
|
|
@@ -4359,8 +4063,6 @@ exports.__private = {
|
|
|
4359
4063
|
embedQueryCached,
|
|
4360
4064
|
compactToolResult,
|
|
4361
4065
|
compactToolHistoryForAgent,
|
|
4362
|
-
extractToolBookingFacts,
|
|
4363
|
-
deriveBookingState,
|
|
4364
4066
|
compactVectorMemoriesForAgent,
|
|
4365
4067
|
isConversationEchoMemory,
|
|
4366
4068
|
compactOperationalStateForAgent,
|
package/package.json
CHANGED