n8n-nodes-tembory 1.1.43 → 1.1.44
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 +8 -1
- package/dist/nodes/Tembory/TemboryMemory.node.js +47 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,14 @@
|
|
|
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.44`.
|
|
6
|
+
|
|
7
|
+
## 1.1.44
|
|
8
|
+
|
|
9
|
+
- Adiciona `toolReuseGuard` no contexto compacto do agente para reduzir repeticao indevida de tools entre turnos.
|
|
10
|
+
- Registra chamadas bem sucedidas recentes com `input_hash` e classifica tools de leitura versus side effect de forma generica.
|
|
11
|
+
- Instrui o agente a consultar `tool_ledger` antes de nova tool e a nao repetir side effects sem pedido explicito do usuario.
|
|
12
|
+
- Remove duplicacoes do payload compacto para manter o contexto balanceado abaixo do limite de regressao.
|
|
6
13
|
|
|
7
14
|
## 1.1.43
|
|
8
15
|
|
|
@@ -2172,17 +2172,56 @@ const shouldCarryPreviousGoal = (intent = '', previousGoal = '') => {
|
|
|
2172
2172
|
return false;
|
|
2173
2173
|
return ['general_message', 'profile_update', 'unknown'].includes(intent);
|
|
2174
2174
|
};
|
|
2175
|
-
const toolNameSuggestsSideEffect = (name = '') =>
|
|
2176
|
-
const
|
|
2175
|
+
const toolNameSuggestsSideEffect = (name = '') => {
|
|
2176
|
+
const text = String(name || '');
|
|
2177
|
+
if (/(?:^|[_\-. ])(check|consult\w*|search|lookup|find|list|get|read|info|inform\w*|disponibilidade|availability)(?:$|[_\-. ])/i.test(text))
|
|
2178
|
+
return false;
|
|
2179
|
+
return /(?:^|[_\-. ])(book|booking|reserv\w*|agend\w*|confirm\w*|cancel\w*|cri\w*|create|update|upsert|set|send|enviar|registr\w*|cadastr\w*|charge|cobran\w*|pagamento|ticket)(?:$|[_\-. ])/i.test(text);
|
|
2180
|
+
};
|
|
2181
|
+
const compactToolPolicyPayload = (value, max = 420) => {
|
|
2182
|
+
const parsed = safeParseToolPayload(value);
|
|
2183
|
+
const cleaned = stripNoisyToolFields(parsed);
|
|
2184
|
+
return truncate(typeof cleaned === 'string' ? cleaned : safeStringify(cleaned), max) || undefined;
|
|
2185
|
+
};
|
|
2186
|
+
const compactSuccessfulToolCallsForPolicy = (toolHistory = [], toolState = {}, maxItems = 10) => {
|
|
2187
|
+
const fromHistory = (Array.isArray(toolHistory) ? toolHistory : [])
|
|
2188
|
+
.filter((tool) => tool && tool.ok !== false && (tool.name || tool.tool_name || tool.tool))
|
|
2189
|
+
.map((tool) => {
|
|
2190
|
+
const name = String(tool.name || tool.tool_name || tool.tool || 'unknown_tool');
|
|
2191
|
+
return cleanContextValue({
|
|
2192
|
+
name,
|
|
2193
|
+
at: tool.at || tool.timestamp,
|
|
2194
|
+
input_hash: stableHash({ name, input: safeParseToolPayload(tool.input) }),
|
|
2195
|
+
side_effect: toolNameSuggestsSideEffect(name),
|
|
2196
|
+
});
|
|
2197
|
+
});
|
|
2198
|
+
const fromToolState = Object.values((toolState || {}).latest_by_name || {}).map((tool) => {
|
|
2199
|
+
const name = String(tool.name || tool.tool || 'unknown_tool');
|
|
2200
|
+
const input = compactToolPolicyPayload(tool.input, 220);
|
|
2201
|
+
return cleanContextValue({
|
|
2202
|
+
name,
|
|
2203
|
+
at: tool.at || tool.timestamp,
|
|
2204
|
+
input_hash: stableHash({ name, input }),
|
|
2205
|
+
side_effect: toolNameSuggestsSideEffect(name),
|
|
2206
|
+
});
|
|
2207
|
+
});
|
|
2208
|
+
return pruneByLimit(fromHistory.length ? fromHistory : fromToolState, maxItems);
|
|
2209
|
+
};
|
|
2210
|
+
const deriveToolRepeatPolicy = ({ intent = '', query = '', executedTools = [], toolState = {}, toolHistory = [] }) => {
|
|
2177
2211
|
const tools = Array.from(new Set(executedTools.filter(Boolean)));
|
|
2178
2212
|
const strictMemoryOnlyTurn = intent === 'conversation_recall' || intent === 'operational_status_question' || hasNoToolRequested(query);
|
|
2179
2213
|
const sideEffectToolCandidates = tools.filter(toolNameSuggestsSideEffect);
|
|
2214
|
+
const successfulToolCalls = compactSuccessfulToolCallsForPolicy(toolHistory, toolState, 10);
|
|
2215
|
+
const referenceToolCandidates = tools.filter((tool) => !toolNameSuggestsSideEffect(tool));
|
|
2180
2216
|
return cleanContextValue({
|
|
2181
2217
|
mode: strictMemoryOnlyTurn ? 'answer_from_memory_when_possible' : 'conditional_reuse',
|
|
2182
2218
|
avoid_repeating_tools_unless_needed: tools,
|
|
2183
2219
|
legacy_do_not_repeat_applies: strictMemoryOnlyTurn,
|
|
2184
2220
|
side_effect_tool_candidates: sideEffectToolCandidates,
|
|
2185
|
-
|
|
2221
|
+
do_not_repeat_side_effect_tools_without_explicit_new_request: sideEffectToolCandidates,
|
|
2222
|
+
answer_from_memory_candidates: referenceToolCandidates,
|
|
2223
|
+
successful_tool_calls: successfulToolCalls,
|
|
2224
|
+
instruction: 'Check tool_ledger before any tool. If same tool/input already succeeded and user did not request new or fresh data, answer from prior result. Never repeat side-effect tools without an explicit new user request.',
|
|
2186
2225
|
});
|
|
2187
2226
|
};
|
|
2188
2227
|
const deriveWorkingMemory = ({ query = '', profileFacts = {}, recentMessages = [], toolHistory = [], operationalState = {}, previous = {} }) => {
|
|
@@ -2278,7 +2317,7 @@ const deriveDecisionState = ({ query = '', toolHistory = [], operationalState =
|
|
|
2278
2317
|
});
|
|
2279
2318
|
};
|
|
2280
2319
|
const executedTools = Array.from(new Set(Object.keys(toolState.counts_by_name || {})));
|
|
2281
|
-
const toolRepeatPolicy = deriveToolRepeatPolicy({ intent, query, executedTools, toolState });
|
|
2320
|
+
const toolRepeatPolicy = deriveToolRepeatPolicy({ intent, query, executedTools, toolState, toolHistory });
|
|
2282
2321
|
const doNotRepeatTools = toolRepeatPolicy.legacy_do_not_repeat_applies ? executedTools : [];
|
|
2283
2322
|
if (toolState.last_successful_tool)
|
|
2284
2323
|
pushDecision('last_successful_tool_recorded', `latest successful tool is ${toolState.last_successful_tool.name}`, 'tool_state records successful tool execution', 'tool_orchestration', { confidence: 0.9, tool: toolState.last_successful_tool.name });
|
|
@@ -2814,8 +2853,9 @@ const compactToolDecisionStateForAgent = (toolDecisionState = {}) => {
|
|
|
2814
2853
|
};
|
|
2815
2854
|
const compactRepeatToolPolicyForAgent = (policy = {}) => cleanContextValue({
|
|
2816
2855
|
mode: policy.mode,
|
|
2817
|
-
|
|
2818
|
-
|
|
2856
|
+
do_not_repeat_side_effect_tools: (policy.do_not_repeat_side_effect_tools_without_explicit_new_request || []).slice(0, 12),
|
|
2857
|
+
answer_from_memory_candidates: (policy.answer_from_memory_candidates || []).slice(0, 12),
|
|
2858
|
+
successful_tool_calls: (policy.successful_tool_calls || []).slice(-8),
|
|
2819
2859
|
instruction: policy.instruction,
|
|
2820
2860
|
});
|
|
2821
2861
|
const compactDecisionStateForAgent = (state = {}) => cleanContextValue({
|
|
@@ -2830,9 +2870,6 @@ const compactDecisionStateForAgent = (state = {}) => cleanContextValue({
|
|
|
2830
2870
|
at: decision.at || decision.updated_at,
|
|
2831
2871
|
})),
|
|
2832
2872
|
do_not_repeat_tools: state.do_not_repeat_tools,
|
|
2833
|
-
repeat_tool_policy: state.repeat_tool_policy ? compactRepeatToolPolicyForAgent(state.repeat_tool_policy) : undefined,
|
|
2834
|
-
avoid_repeating_tools_unless_needed: state.avoid_repeating_tools_unless_needed,
|
|
2835
|
-
tool_decision_state: state.tool_decision_state ? compactToolDecisionStateForAgent(state.tool_decision_state) : undefined,
|
|
2836
2873
|
latest_tool: state.latest_tool ? cleanContextValue({
|
|
2837
2874
|
name: state.latest_tool.name,
|
|
2838
2875
|
status: state.latest_tool.status || (state.latest_tool.ok === false ? 'failed' : 'ok'),
|
|
@@ -3700,7 +3737,6 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
|
|
|
3700
3737
|
value: cleanContextValue({
|
|
3701
3738
|
current_intent: (decisionState || {}).current_intent || workingMemory.last_user_intent,
|
|
3702
3739
|
latest_tool: ((decisionState || {}).latest_tool || (operationalState || {}).last_tool || undefined),
|
|
3703
|
-
repeat_tool_policy: (decisionState || {}).repeat_tool_policy,
|
|
3704
3740
|
avoid_repeating_tools_unless_needed: ((decisionState || {}).avoid_repeating_tools_unless_needed || []).slice(0, 12),
|
|
3705
3741
|
do_not_repeat_tools_legacy: ((decisionState || {}).do_not_repeat_tools || []).slice(0, 12),
|
|
3706
3742
|
instruction: actionDirective || workingMemory.next_expected_action || 'Continue according to the agent prompt.',
|
|
@@ -3757,6 +3793,7 @@ const buildContextMessages = ({ payloadFormat, query, userId, profileFacts, work
|
|
|
3757
3793
|
state: minimalState,
|
|
3758
3794
|
workingMemory: sectionValue('working_memory'),
|
|
3759
3795
|
decisionState: sectionValue('decision_state'),
|
|
3796
|
+
toolReuseGuard: compactRepeatToolPolicyForAgent((decisionState || {}).repeat_tool_policy || {}),
|
|
3760
3797
|
operationalState: sectionValue('operational_state'),
|
|
3761
3798
|
actionLedger: sectionValue('action_ledger'),
|
|
3762
3799
|
memoryCompression: sectionValue('memory_compression'),
|
package/package.json
CHANGED