n8n-nodes-tembory 1.1.39 → 1.1.41
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.
- package/README.md +13 -1
- package/dist/nodes/Tembory/TemboryMemory.node.js +227 -24
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
Node de memoria operacional da Tembory para agentes de IA no n8n.
|
|
4
4
|
|
|
5
|
-
Versao atual: `1.1.
|
|
5
|
+
Versao atual: `1.1.41`.
|
|
6
|
+
|
|
7
|
+
## 1.1.41
|
|
8
|
+
|
|
9
|
+
- Padroniza a saida visual do node com `visualSchema`, `memorySummary` e `toolLog` tanto no `loadMemoryVariables` quanto no `saveContext`.
|
|
10
|
+
- Mantem `toolEvents` para compatibilidade, mas agora tambem mostra `inputParsed`, `outputParsed`, timestamps e `facts` com IDs operacionais quando existirem.
|
|
11
|
+
- Aumenta a visibilidade do historico recente de tools no resumo visual para evitar esconder eventos importantes no debug humano.
|
|
12
|
+
|
|
13
|
+
## 1.1.40
|
|
14
|
+
|
|
15
|
+
- Extrai fatos operacionais path aware de inputs e outputs de tools, preservando IDs como `serviceId`, `providerId`, `locationId`, `customerId`, `reservationId` e `bookingId`.
|
|
16
|
+
- Injeta esses fatos em `operationalState`, `actionLedger`, `toolLedger` e `action_directive`.
|
|
17
|
+
- Corrige o risco de o Agent usar `serviceId` antigo de memoria vetorial quando o `check_availabilities` mais recente ja retornou o ID correto para o `Booking`.
|
|
6
18
|
|
|
7
19
|
## 1.1.39
|
|
8
20
|
|
|
@@ -489,6 +489,7 @@ const deriveOperationalState = (toolHistory = [], profileFacts = {}, recentMessa
|
|
|
489
489
|
const name = String(tool.name || 'unknown_tool');
|
|
490
490
|
const compactInput = compactToolPayload(safeParseToolPayload(tool.input));
|
|
491
491
|
const compactResult = maybeToolResult(tool, includeResults);
|
|
492
|
+
const facts = extractToolOperationalFacts(tool);
|
|
492
493
|
const reason = truncate(String(tool.reason || tool.decision || tool.why || tool.source || 'recorded tool call'), 260);
|
|
493
494
|
toolCountsByName[name] = (toolCountsByName[name] || 0) + 1;
|
|
494
495
|
latestByName[name] = {
|
|
@@ -496,6 +497,7 @@ const deriveOperationalState = (toolHistory = [], profileFacts = {}, recentMessa
|
|
|
496
497
|
ok: tool.ok !== false,
|
|
497
498
|
at: tool.at || null,
|
|
498
499
|
input: compactInput,
|
|
500
|
+
facts,
|
|
499
501
|
result: compactResult,
|
|
500
502
|
reason,
|
|
501
503
|
source: tool.source || 'unknown',
|
|
@@ -507,6 +509,7 @@ const deriveOperationalState = (toolHistory = [], profileFacts = {}, recentMessa
|
|
|
507
509
|
at: tool.at || null,
|
|
508
510
|
reason,
|
|
509
511
|
input: compactInput,
|
|
512
|
+
facts,
|
|
510
513
|
output: compactResult,
|
|
511
514
|
}));
|
|
512
515
|
if (tool.ok === false)
|
|
@@ -538,6 +541,7 @@ const deriveOperationalState = (toolHistory = [], profileFacts = {}, recentMessa
|
|
|
538
541
|
last_successful_tool: successfulTools.length ? {
|
|
539
542
|
name: successfulTools[successfulTools.length - 1].name,
|
|
540
543
|
at: successfulTools[successfulTools.length - 1].at || null,
|
|
544
|
+
facts: extractToolOperationalFacts(successfulTools[successfulTools.length - 1]),
|
|
541
545
|
result: maybeToolResult(successfulTools[successfulTools.length - 1], includeResults),
|
|
542
546
|
} : null,
|
|
543
547
|
},
|
|
@@ -556,6 +560,7 @@ const deriveActionLedger = (toolHistory = [], maxItems = 20, includeResults = tr
|
|
|
556
560
|
status: tool.ok === false ? 'failed' : 'ok',
|
|
557
561
|
reason: truncate(String(tool.reason || tool.decision || tool.why || tool.source || 'recorded tool call'), 260),
|
|
558
562
|
input: compactToolPayload(safeParseToolPayload(tool.input)),
|
|
563
|
+
facts: extractToolOperationalFacts(tool),
|
|
559
564
|
result: maybeToolResult(tool, includeResults),
|
|
560
565
|
at: tool.at || null,
|
|
561
566
|
source: tool.source || 'unknown',
|
|
@@ -2094,16 +2099,25 @@ const buildActionDirective = ({ workingMemory = {}, operationalState = {} }) =>
|
|
|
2094
2099
|
return null;
|
|
2095
2100
|
const toolState = (operationalState || {}).tool_state || {};
|
|
2096
2101
|
const latestForTool = ((toolState.latest_by_name || {})[tool]) || null;
|
|
2102
|
+
const recentToolEvidence = pruneByLimit((toolState.recent_sequence || [])
|
|
2103
|
+
.filter((item) => item && item.status !== 'failed')
|
|
2104
|
+
.map((item) => cleanContextValue({
|
|
2105
|
+
tool: item.tool,
|
|
2106
|
+
at: item.at,
|
|
2107
|
+
facts: item.facts,
|
|
2108
|
+
}))
|
|
2109
|
+
.filter((item) => item && item.facts), 6);
|
|
2097
2110
|
return cleanContextValue({
|
|
2098
2111
|
required_tool: tool,
|
|
2099
2112
|
next_expected_action: next,
|
|
2113
|
+
evidence_from_recent_tools: recentToolEvidence,
|
|
2100
2114
|
tool_state: {
|
|
2101
2115
|
last_tool: (operationalState || {}).last_tool || null,
|
|
2102
2116
|
required_tool_last_result: latestForTool,
|
|
2103
2117
|
counts_by_name: toolState.counts_by_name || {},
|
|
2104
2118
|
failed_by_name: toolState.failed_by_name || {},
|
|
2105
2119
|
},
|
|
2106
|
-
instruction: `
|
|
2120
|
+
instruction: `call ${tool} now if the agent prompt requires it. Use tool evidence for exact IDs. Do not complete side effects from memory.`,
|
|
2107
2121
|
});
|
|
2108
2122
|
};
|
|
2109
2123
|
const inferToolGuard = ({ query, recentMessages, toolHistory, vectorMemories }) => {
|
|
@@ -2520,6 +2534,152 @@ const normalizeToolResultEnvelope = (value) => {
|
|
|
2520
2534
|
}
|
|
2521
2535
|
return parsed;
|
|
2522
2536
|
};
|
|
2537
|
+
const normalizeFactKey = (key = '') => String(key || '').toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
2538
|
+
const scalarFactValue = (value) => {
|
|
2539
|
+
if (value === undefined || value === null || value === '')
|
|
2540
|
+
return undefined;
|
|
2541
|
+
if (['string', 'number', 'boolean'].includes(typeof value))
|
|
2542
|
+
return value;
|
|
2543
|
+
return undefined;
|
|
2544
|
+
};
|
|
2545
|
+
const pushCandidate = (facts, bucket, value, path) => {
|
|
2546
|
+
const scalar = scalarFactValue(value);
|
|
2547
|
+
if (scalar === undefined)
|
|
2548
|
+
return;
|
|
2549
|
+
facts[bucket] = facts[bucket] || [];
|
|
2550
|
+
if (!facts[bucket].some((item) => String(item.value) === String(scalar) && item.path === path)) {
|
|
2551
|
+
facts[bucket].push({ value: scalar, path });
|
|
2552
|
+
}
|
|
2553
|
+
};
|
|
2554
|
+
const firstCandidateValue = (items = []) => items.length ? items[0].value : undefined;
|
|
2555
|
+
const extractOperationalFactsFromValue = (value, maxCandidates = 8) => {
|
|
2556
|
+
const parsed = normalizeToolResultEnvelope(value);
|
|
2557
|
+
const facts = {
|
|
2558
|
+
serviceIdCandidates: [],
|
|
2559
|
+
providerIdCandidates: [],
|
|
2560
|
+
locationIdCandidates: [],
|
|
2561
|
+
customerIdCandidates: [],
|
|
2562
|
+
reservationIdCandidates: [],
|
|
2563
|
+
bookingIdCandidates: [],
|
|
2564
|
+
confirmationIdCandidates: [],
|
|
2565
|
+
serviceNameCandidates: [],
|
|
2566
|
+
providerNameCandidates: [],
|
|
2567
|
+
statusCandidates: [],
|
|
2568
|
+
timeCandidates: [],
|
|
2569
|
+
dateCandidates: [],
|
|
2570
|
+
};
|
|
2571
|
+
const seen = new Set();
|
|
2572
|
+
let visited = 0;
|
|
2573
|
+
const visit = (item, path = []) => {
|
|
2574
|
+
if (visited > 220 || item === undefined || item === null)
|
|
2575
|
+
return;
|
|
2576
|
+
if (typeof item !== 'object')
|
|
2577
|
+
return;
|
|
2578
|
+
if (seen.has(item))
|
|
2579
|
+
return;
|
|
2580
|
+
seen.add(item);
|
|
2581
|
+
visited += 1;
|
|
2582
|
+
if (Array.isArray(item)) {
|
|
2583
|
+
item.slice(0, 12).forEach((entry, index) => visit(entry, path.concat(String(index))));
|
|
2584
|
+
return;
|
|
2585
|
+
}
|
|
2586
|
+
for (const [rawKey, rawValue] of Object.entries(item)) {
|
|
2587
|
+
const key = normalizeFactKey(rawKey);
|
|
2588
|
+
const nextPath = path.concat(rawKey);
|
|
2589
|
+
const pathText = nextPath.join('.');
|
|
2590
|
+
const parentText = path.join('.').toLowerCase();
|
|
2591
|
+
const parentSuggestsService = /(^|\.)(service|services|servico|servicos|especialidade|especialidades)(\.|$)/i.test(parentText);
|
|
2592
|
+
const parentSuggestsProvider = /(^|\.)(provider|providers|veterinario|veterinarios|vet|vets|professional|profissional|profissionais)(\.|$)/i.test(parentText);
|
|
2593
|
+
const parentSuggestsLocation = /(^|\.)(location|locations|local|locais|unidade|unidades)(\.|$)/i.test(parentText);
|
|
2594
|
+
if (key === 'serviceid' || key === 'servicoid' || (key === 'id' && parentSuggestsService))
|
|
2595
|
+
pushCandidate(facts, 'serviceIdCandidates', rawValue, pathText);
|
|
2596
|
+
if (key === 'providerid' || key === 'veterinarioid' || key === 'vetid' || (key === 'id' && parentSuggestsProvider))
|
|
2597
|
+
pushCandidate(facts, 'providerIdCandidates', rawValue, pathText);
|
|
2598
|
+
if (key === 'locationid' || key === 'localid' || key === 'unidadeid' || (key === 'id' && parentSuggestsLocation))
|
|
2599
|
+
pushCandidate(facts, 'locationIdCandidates', rawValue, pathText);
|
|
2600
|
+
if (key === 'customerid' || key === 'clienteid')
|
|
2601
|
+
pushCandidate(facts, 'customerIdCandidates', rawValue, pathText);
|
|
2602
|
+
if (key === 'reservationid' || key === 'reservaid')
|
|
2603
|
+
pushCandidate(facts, 'reservationIdCandidates', rawValue, pathText);
|
|
2604
|
+
if (key === 'bookingid' || key === 'appointmentid' || key === 'agendamentoid')
|
|
2605
|
+
pushCandidate(facts, 'bookingIdCandidates', rawValue, pathText);
|
|
2606
|
+
if (key === 'confirmationid')
|
|
2607
|
+
pushCandidate(facts, 'confirmationIdCandidates', rawValue, pathText);
|
|
2608
|
+
if (key === 'servicename' || key === 'servico' || key === 'especialidade' || (key === 'name' && parentSuggestsService))
|
|
2609
|
+
pushCandidate(facts, 'serviceNameCandidates', rawValue, pathText);
|
|
2610
|
+
if (key === 'providername' || key === 'veterinarioname' || key === 'nomeveterinario' || (key === 'name' && parentSuggestsProvider))
|
|
2611
|
+
pushCandidate(facts, 'providerNameCandidates', rawValue, pathText);
|
|
2612
|
+
if (key === 'status' || key === 'state')
|
|
2613
|
+
pushCandidate(facts, 'statusCandidates', rawValue, pathText);
|
|
2614
|
+
if (key === 'horario' || key === 'horarios' || key === 'time' || key === 'start' || key === 'end')
|
|
2615
|
+
pushCandidate(facts, 'timeCandidates', rawValue, pathText);
|
|
2616
|
+
if (key === 'date' || key === 'data' || key === 'datadisponivel')
|
|
2617
|
+
pushCandidate(facts, 'dateCandidates', rawValue, pathText);
|
|
2618
|
+
if (rawValue && typeof rawValue === 'object')
|
|
2619
|
+
visit(rawValue, nextPath);
|
|
2620
|
+
}
|
|
2621
|
+
};
|
|
2622
|
+
visit(parsed);
|
|
2623
|
+
const compactCandidates = (items = []) => items.slice(0, maxCandidates);
|
|
2624
|
+
return cleanContextValue({
|
|
2625
|
+
ids: {
|
|
2626
|
+
serviceId: firstCandidateValue(facts.serviceIdCandidates),
|
|
2627
|
+
providerId: firstCandidateValue(facts.providerIdCandidates),
|
|
2628
|
+
locationId: firstCandidateValue(facts.locationIdCandidates),
|
|
2629
|
+
customerId: firstCandidateValue(facts.customerIdCandidates),
|
|
2630
|
+
reservationId: firstCandidateValue(facts.reservationIdCandidates),
|
|
2631
|
+
bookingId: firstCandidateValue(facts.bookingIdCandidates),
|
|
2632
|
+
confirmationId: firstCandidateValue(facts.confirmationIdCandidates),
|
|
2633
|
+
},
|
|
2634
|
+
labels: {
|
|
2635
|
+
serviceName: firstCandidateValue(facts.serviceNameCandidates),
|
|
2636
|
+
providerName: firstCandidateValue(facts.providerNameCandidates),
|
|
2637
|
+
status: firstCandidateValue(facts.statusCandidates),
|
|
2638
|
+
date: firstCandidateValue(facts.dateCandidates),
|
|
2639
|
+
time: firstCandidateValue(facts.timeCandidates),
|
|
2640
|
+
},
|
|
2641
|
+
candidates: {
|
|
2642
|
+
serviceIds: compactCandidates(facts.serviceIdCandidates),
|
|
2643
|
+
providerIds: compactCandidates(facts.providerIdCandidates),
|
|
2644
|
+
locationIds: compactCandidates(facts.locationIdCandidates),
|
|
2645
|
+
},
|
|
2646
|
+
});
|
|
2647
|
+
};
|
|
2648
|
+
const mergeOperationalFactObjects = (primary = {}, secondary = {}) => {
|
|
2649
|
+
const pick = (path) => {
|
|
2650
|
+
const read = (source) => path.reduce((acc, key) => acc && acc[key] !== undefined ? acc[key] : undefined, source);
|
|
2651
|
+
return read(primary) !== undefined ? read(primary) : read(secondary);
|
|
2652
|
+
};
|
|
2653
|
+
return cleanContextValue({
|
|
2654
|
+
ids: {
|
|
2655
|
+
serviceId: pick(['ids', 'serviceId']),
|
|
2656
|
+
providerId: pick(['ids', 'providerId']),
|
|
2657
|
+
locationId: pick(['ids', 'locationId']),
|
|
2658
|
+
customerId: pick(['ids', 'customerId']),
|
|
2659
|
+
reservationId: pick(['ids', 'reservationId']),
|
|
2660
|
+
bookingId: pick(['ids', 'bookingId']),
|
|
2661
|
+
confirmationId: pick(['ids', 'confirmationId']),
|
|
2662
|
+
},
|
|
2663
|
+
labels: {
|
|
2664
|
+
serviceName: pick(['labels', 'serviceName']),
|
|
2665
|
+
providerName: pick(['labels', 'providerName']),
|
|
2666
|
+
status: pick(['labels', 'status']),
|
|
2667
|
+
date: pick(['labels', 'date']),
|
|
2668
|
+
time: pick(['labels', 'time']),
|
|
2669
|
+
},
|
|
2670
|
+
candidates: {
|
|
2671
|
+
serviceIds: ((primary.candidates || {}).serviceIds || (secondary.candidates || {}).serviceIds || []).slice(0, 8),
|
|
2672
|
+
providerIds: ((primary.candidates || {}).providerIds || (secondary.candidates || {}).providerIds || []).slice(0, 8),
|
|
2673
|
+
locationIds: ((primary.candidates || {}).locationIds || (secondary.candidates || {}).locationIds || []).slice(0, 8),
|
|
2674
|
+
},
|
|
2675
|
+
});
|
|
2676
|
+
};
|
|
2677
|
+
const extractToolOperationalFacts = (tool = {}) => {
|
|
2678
|
+
const inputFacts = extractOperationalFactsFromValue(safeParseToolPayload(tool.input));
|
|
2679
|
+
const outputFacts = extractOperationalFactsFromValue(tool.result);
|
|
2680
|
+
const facts = mergeOperationalFactObjects(outputFacts, inputFacts);
|
|
2681
|
+
return Object.keys(facts || {}).length ? facts : undefined;
|
|
2682
|
+
};
|
|
2523
2683
|
const compactParsedToolOutputForSideChannel = (parsed) => {
|
|
2524
2684
|
if (parsed === undefined || parsed === null)
|
|
2525
2685
|
return undefined;
|
|
@@ -2559,6 +2719,7 @@ const compactToolHistoryForAgent = (toolHistory = [], maxItems = 6, includeResul
|
|
|
2559
2719
|
at: tool.at,
|
|
2560
2720
|
reason: truncate(String(tool.reason || tool.decision || tool.why || tool.source || 'recorded tool call'), 140),
|
|
2561
2721
|
input: truncate(String(tool.input || ''), 500) || undefined,
|
|
2722
|
+
facts: extractToolOperationalFacts(tool),
|
|
2562
2723
|
result: includeResults ? compactToolResult(tool.result, 1200) : undefined,
|
|
2563
2724
|
}));
|
|
2564
2725
|
const cleanContextValue = (value) => {
|
|
@@ -2641,7 +2802,7 @@ const compactDecisionStateForAgent = (state = {}) => cleanContextValue({
|
|
|
2641
2802
|
const compactOperationalStateForAgent = (state = {}) => {
|
|
2642
2803
|
const counts = state.tool_counts || {};
|
|
2643
2804
|
const toolState = state.tool_state || {};
|
|
2644
|
-
return {
|
|
2805
|
+
return cleanContextValue({
|
|
2645
2806
|
last_tool: state.last_tool || null,
|
|
2646
2807
|
tool_counts: {
|
|
2647
2808
|
total: counts.total || 0,
|
|
@@ -2655,8 +2816,7 @@ const compactOperationalStateForAgent = (state = {}) => {
|
|
|
2655
2816
|
last_successful_tool: toolState.last_successful_tool || undefined,
|
|
2656
2817
|
} : undefined,
|
|
2657
2818
|
blocked_without_context: state.blocked_without_context || [],
|
|
2658
|
-
|
|
2659
|
-
};
|
|
2819
|
+
});
|
|
2660
2820
|
};
|
|
2661
2821
|
const compactMemoryCompressionForAgent = (compression = {}) => ({
|
|
2662
2822
|
turn_summary: (compression.turn_summary || []).slice(-3),
|
|
@@ -2846,6 +3006,16 @@ const invokeConnectedModelSummary = async (connectedLanguageModel, summaryInput,
|
|
|
2846
3006
|
]);
|
|
2847
3007
|
return cleanModelSummaryText(response, Number(adv.connectedModelSummaryMaxChars || 1200));
|
|
2848
3008
|
};
|
|
3009
|
+
const VISUAL_SCHEMA_VERSION = 'tembory.visual.v1';
|
|
3010
|
+
const TOOL_LOG_VISUAL_SCHEMA_VERSION = 'tembory.visual.v1.toolLog';
|
|
3011
|
+
const SIDE_CHANNEL_TOOL_EVENT_MAX = 12;
|
|
3012
|
+
const SIDE_CHANNEL_SAVE_TOOL_EVENT_MAX = 20;
|
|
3013
|
+
const compactParsedToolInputForSideChannel = (input) => {
|
|
3014
|
+
const parsed = safeParseToolPayload(input);
|
|
3015
|
+
if (!parsed || typeof parsed !== 'object')
|
|
3016
|
+
return undefined;
|
|
3017
|
+
return cleanContextValue(stripNoisyToolFields(parsed));
|
|
3018
|
+
};
|
|
2849
3019
|
const compactToolAuditForSideChannel = (tool = {}) => {
|
|
2850
3020
|
const capturedAt = tool.at || tool.timestamp;
|
|
2851
3021
|
const rawResult = tool.result !== undefined ? tool.result : tool.output !== undefined ? tool.output : tool.observation;
|
|
@@ -2859,10 +3029,36 @@ const compactToolAuditForSideChannel = (tool = {}) => {
|
|
|
2859
3029
|
toolTimestamp: toolResultTimestampFromParsed(parsedResult),
|
|
2860
3030
|
toolStatus: parsedResult && typeof parsedResult === 'object' && !Array.isArray(parsedResult) ? parsedResult.status : undefined,
|
|
2861
3031
|
input: truncate(String(tool.input || tool.tool_args || tool.normalized_args || ''), 300) || undefined,
|
|
3032
|
+
inputParsed: compactParsedToolInputForSideChannel(tool.input || tool.tool_args || tool.normalized_args),
|
|
2862
3033
|
output: compactToolResult(rawResult, 800),
|
|
2863
3034
|
outputParsed: compactParsedToolOutputForSideChannel(parsedResult),
|
|
3035
|
+
facts: extractToolOperationalFacts(tool),
|
|
2864
3036
|
});
|
|
2865
3037
|
};
|
|
3038
|
+
const compactToolEventsForSideChannel = (toolItems = [], maxItems = SIDE_CHANNEL_TOOL_EVENT_MAX) => pruneByLimit(toolItems || [], maxItems)
|
|
3039
|
+
.map((tool) => compactToolAuditForSideChannel(tool || {}))
|
|
3040
|
+
.filter((tool) => tool && Object.keys(tool).length);
|
|
3041
|
+
const buildToolLogForSideChannel = (toolEvents = [], totalCount, maxItems = SIDE_CHANNEL_TOOL_EVENT_MAX) => {
|
|
3042
|
+
const events = Array.isArray(toolEvents) ? toolEvents : [];
|
|
3043
|
+
const count = typeof totalCount === 'number' ? totalCount : events.length;
|
|
3044
|
+
return {
|
|
3045
|
+
schema: TOOL_LOG_VISUAL_SCHEMA_VERSION,
|
|
3046
|
+
count,
|
|
3047
|
+
names: events.map((tool) => tool.name).filter(Boolean).slice(0, maxItems),
|
|
3048
|
+
events,
|
|
3049
|
+
truncated: count > events.length,
|
|
3050
|
+
maxEvents: maxItems,
|
|
3051
|
+
};
|
|
3052
|
+
};
|
|
3053
|
+
const keepVisibleToolLogArrays = (payload = {}) => {
|
|
3054
|
+
if (payload.toolLog) {
|
|
3055
|
+
if (!Array.isArray(payload.toolLog.names))
|
|
3056
|
+
payload.toolLog.names = [];
|
|
3057
|
+
if (!Array.isArray(payload.toolLog.events))
|
|
3058
|
+
payload.toolLog.events = [];
|
|
3059
|
+
}
|
|
3060
|
+
return payload;
|
|
3061
|
+
};
|
|
2866
3062
|
const compactMessageForSideChannel = (message = {}) => {
|
|
2867
3063
|
const type = messageTypeOf(message) || String(message.role || 'message').toLowerCase();
|
|
2868
3064
|
const role = type === 'human' ? 'user' : type === 'ai' ? 'assistant' : type || 'message';
|
|
@@ -2913,21 +3109,21 @@ const compactConversationTimelineForSideChannel = (conversation = {}, maxItems =
|
|
|
2913
3109
|
const summarizeSaveContextForSideChannel = (input = {}, output = {}, chatHistory = []) => {
|
|
2914
3110
|
const inputMessage = input?.input || input?.chatInput || input?.query || input?.question || input?.text || input?.message || '';
|
|
2915
3111
|
const outputMessage = output?.output || output?.response || output?.text || output?.message || output?.answer || '';
|
|
2916
|
-
const
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
return cleanContextValue({
|
|
3112
|
+
const toolCalls = extractToolCalls(output || {});
|
|
3113
|
+
const toolEvents = compactToolEventsForSideChannel(toolCalls, SIDE_CHANNEL_SAVE_TOOL_EVENT_MAX);
|
|
3114
|
+
return keepVisibleToolLogArrays(cleanContextValue({
|
|
3115
|
+
visualSchema: VISUAL_SCHEMA_VERSION,
|
|
2921
3116
|
messagesAfterSave: Array.isArray(chatHistory) ? chatHistory.length : 0,
|
|
2922
3117
|
savedMessages: Array.isArray(chatHistory)
|
|
2923
3118
|
? chatHistory.slice(-6).map((message) => compactMessageForSideChannel(message))
|
|
2924
3119
|
: undefined,
|
|
2925
3120
|
userInput: inputMessage ? truncate(String(inputMessage), 500) : undefined,
|
|
2926
3121
|
assistantOutput: outputMessage ? truncate(String(outputMessage), 700) : undefined,
|
|
2927
|
-
toolCallsCaptured:
|
|
3122
|
+
toolCallsCaptured: toolCalls.length,
|
|
2928
3123
|
toolNames: toolEvents.map((tool) => tool.name).filter(Boolean),
|
|
3124
|
+
toolLog: buildToolLogForSideChannel(toolEvents, toolCalls.length, SIDE_CHANNEL_SAVE_TOOL_EVENT_MAX),
|
|
2929
3125
|
toolEvents,
|
|
2930
|
-
});
|
|
3126
|
+
}));
|
|
2931
3127
|
};
|
|
2932
3128
|
const compactMemoryEventPayload = (payload = {}) => {
|
|
2933
3129
|
const compact = { ...(payload || {}) };
|
|
@@ -2937,18 +3133,20 @@ const compactMemoryEventPayload = (payload = {}) => {
|
|
|
2937
3133
|
.map((tool) => (tool && (tool.name || tool.tool_name || tool.tool)) || '')
|
|
2938
3134
|
.filter(Boolean)
|
|
2939
3135
|
.slice(0, 12);
|
|
2940
|
-
compact.toolEvents = compact.toolCalls
|
|
2941
|
-
|
|
2942
|
-
.filter((tool) => tool && Object.keys(tool).length)
|
|
2943
|
-
.slice(0, 8);
|
|
3136
|
+
compact.toolEvents = compactToolEventsForSideChannel(compact.toolCalls, SIDE_CHANNEL_TOOL_EVENT_MAX);
|
|
3137
|
+
compact.toolLog = buildToolLogForSideChannel(compact.toolEvents, compact.toolCalls.length, SIDE_CHANNEL_TOOL_EVENT_MAX);
|
|
2944
3138
|
delete compact.toolCalls;
|
|
2945
3139
|
}
|
|
3140
|
+
if (!compact.visualSchema)
|
|
3141
|
+
compact.visualSchema = VISUAL_SCHEMA_VERSION;
|
|
3142
|
+
if (Array.isArray(compact.toolEvents) && !compact.toolLog)
|
|
3143
|
+
compact.toolLog = buildToolLogForSideChannel(compact.toolEvents, compact.toolCallsCaptured, SIDE_CHANNEL_TOOL_EVENT_MAX);
|
|
2946
3144
|
for (const key of ['input', 'output', 'values', 'chatHistory', 'context', 'contextText', 'diagnostics']) {
|
|
2947
3145
|
if (compact[key] !== undefined)
|
|
2948
3146
|
compact[`${key}Chars`] = typeof compact[key] === 'string' ? compact[key].length : safeStringify(compact[key]).length;
|
|
2949
3147
|
delete compact[key];
|
|
2950
3148
|
}
|
|
2951
|
-
return compact;
|
|
3149
|
+
return keepVisibleToolLogArrays(compact);
|
|
2952
3150
|
};
|
|
2953
3151
|
const compactLastSaveForSideChannel = (lastSave = {}) => cleanContextValue({
|
|
2954
3152
|
saved: lastSave.saved,
|
|
@@ -3099,6 +3297,7 @@ const summarizeMemoryMessagesForSideChannel = (messages = []) => {
|
|
|
3099
3297
|
const fullDedupeSummary = parsed.dedupeSummary || parsed.diagnostics?.dedupeSummary || undefined;
|
|
3100
3298
|
const loadedSections = loadedSectionsForSideChannel(parsed, memoryAudit);
|
|
3101
3299
|
const agentContextBudget = agentContextBudgetForSideChannel(list, parsed);
|
|
3300
|
+
summary.visualSchema = VISUAL_SCHEMA_VERSION;
|
|
3102
3301
|
summary.userId = parsed.userId;
|
|
3103
3302
|
summary.project = parsed.project || undefined;
|
|
3104
3303
|
summary.retrievalMode = parsed.retrievalMode;
|
|
@@ -3122,12 +3321,11 @@ const summarizeMemoryMessagesForSideChannel = (messages = []) => {
|
|
|
3122
3321
|
} : undefined,
|
|
3123
3322
|
});
|
|
3124
3323
|
summary.conversationTimeline = compactConversationTimelineForSideChannel(conversation, 4);
|
|
3324
|
+
const visibleToolEvents = compactToolEventsForSideChannel(toolItems, SIDE_CHANNEL_TOOL_EVENT_MAX);
|
|
3125
3325
|
summary.toolCount = toolItems.length || tools.count || parsed.operationalState?.tool_counts?.total || undefined;
|
|
3126
3326
|
summary.toolNames = toolItems.map((tool) => tool.name || tool.tool_name).filter(Boolean).slice(0, 12);
|
|
3127
|
-
summary.
|
|
3128
|
-
|
|
3129
|
-
.map((tool) => compactToolAuditForSideChannel(tool || {}))
|
|
3130
|
-
.filter((tool) => tool && Object.keys(tool).length);
|
|
3327
|
+
summary.toolLog = buildToolLogForSideChannel(visibleToolEvents, toolItems.length || summary.toolCount || visibleToolEvents.length, SIDE_CHANNEL_TOOL_EVENT_MAX);
|
|
3328
|
+
summary.toolEvents = visibleToolEvents;
|
|
3131
3329
|
summary.lastTool = tools.last_successful_tool
|
|
3132
3330
|
? {
|
|
3133
3331
|
name: tools.last_successful_tool.name,
|
|
@@ -3217,7 +3415,7 @@ const wrapTemboryMemory = (memory, ctx, memoryKey, itemIndex = 0) => new Proxy(m
|
|
|
3217
3415
|
if (prop === 'loadMemoryVariables') {
|
|
3218
3416
|
return async (values = {}) => {
|
|
3219
3417
|
const { index } = ctx.addInputData(n8n_workflow_1.NodeConnectionTypes.AiMemory, [
|
|
3220
|
-
[{ json: { action: 'loadMemoryVariables', valuesChars: JSON.stringify(values || {}).length } }],
|
|
3418
|
+
[{ json: { action: 'loadMemoryVariables', visualSchema: VISUAL_SCHEMA_VERSION, valuesChars: JSON.stringify(values || {}).length } }],
|
|
3221
3419
|
]);
|
|
3222
3420
|
try {
|
|
3223
3421
|
const response = await target.loadMemoryVariables(values);
|
|
@@ -3227,6 +3425,7 @@ const wrapTemboryMemory = (memory, ctx, memoryKey, itemIndex = 0) => new Proxy(m
|
|
|
3227
3425
|
[{
|
|
3228
3426
|
json: {
|
|
3229
3427
|
action: 'loadMemoryVariables',
|
|
3428
|
+
visualSchema: VISUAL_SCHEMA_VERSION,
|
|
3230
3429
|
messages,
|
|
3231
3430
|
memorySummary: summarizeMemoryMessagesForSideChannel(memoryMessages),
|
|
3232
3431
|
},
|
|
@@ -3428,7 +3627,7 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
|
|
|
3428
3627
|
statusAnswerMaterial: sectionValue('status_answer_material'),
|
|
3429
3628
|
action_directive: directive ? cleanContextValue({
|
|
3430
3629
|
required_tool: directive.required_tool,
|
|
3431
|
-
|
|
3630
|
+
evidence_from_recent_tools: directive.evidence_from_recent_tools,
|
|
3432
3631
|
instruction: directive.instruction,
|
|
3433
3632
|
}) : undefined,
|
|
3434
3633
|
turnBrief: compactTurnBriefForAgent(sectionValue('turn_brief')),
|
|
@@ -3879,14 +4078,15 @@ class TemboryMemory {
|
|
|
3879
4078
|
const loadCache = new Map();
|
|
3880
4079
|
const recordMemoryEvent = (action, payload = {}, error) => {
|
|
3881
4080
|
const { index } = this.addInputData(n8n_workflow_1.NodeConnectionTypes.AiMemory, [
|
|
3882
|
-
[{ json: { action } }],
|
|
4081
|
+
[{ json: { action, visualSchema: VISUAL_SCHEMA_VERSION } }],
|
|
3883
4082
|
]);
|
|
3884
4083
|
if (error) {
|
|
3885
4084
|
this.addOutputData(n8n_workflow_1.NodeConnectionTypes.AiMemory, index, error);
|
|
3886
4085
|
return;
|
|
3887
4086
|
}
|
|
4087
|
+
const compactPayload = compactMemoryEventPayload(payload);
|
|
3888
4088
|
this.addOutputData(n8n_workflow_1.NodeConnectionTypes.AiMemory, index, [
|
|
3889
|
-
[{ json: { action, ...
|
|
4089
|
+
[{ json: { action, visualSchema: VISUAL_SCHEMA_VERSION, memorySummary: compactPayload, ...compactPayload } }],
|
|
3890
4090
|
]);
|
|
3891
4091
|
};
|
|
3892
4092
|
const memory = {
|
|
@@ -5222,6 +5422,7 @@ class TemboryMemory {
|
|
|
5222
5422
|
}
|
|
5223
5423
|
const json = {
|
|
5224
5424
|
action: 'loadMemoryVariables',
|
|
5425
|
+
visualSchema: VISUAL_SCHEMA_VERSION,
|
|
5225
5426
|
messages: Array.isArray(payload) ? payload.length : 0,
|
|
5226
5427
|
memorySummary: summarizeMemoryMessagesForSideChannel(payload),
|
|
5227
5428
|
};
|
|
@@ -5298,6 +5499,8 @@ exports.__private = {
|
|
|
5298
5499
|
contextSizeOfMessages,
|
|
5299
5500
|
embedQueryCached,
|
|
5300
5501
|
compactToolResult,
|
|
5502
|
+
compactToolAuditForSideChannel,
|
|
5503
|
+
buildToolLogForSideChannel,
|
|
5301
5504
|
compactToolHistoryForAgent,
|
|
5302
5505
|
compactVectorMemoriesForAgent,
|
|
5303
5506
|
isConversationEchoMemory,
|
package/package.json
CHANGED