Skip to content

Improve Tool Mapping - #72

Open
kere-nel wants to merge 1 commit into
mainfrom
feat/tool-mapping-auto-derive
Open

Improve Tool Mapping #72
kere-nel wants to merge 1 commit into
mainfrom
feat/tool-mapping-auto-derive

Conversation

@kere-nel

@kere-nel kere-nel commented May 8, 2026

Copy link
Copy Markdown
Contributor

Expands TOOL_TO_MODULE with explicit entries for sessions_, memory_, agent_*, and update_plan so these tools resolve to meaningful module/method pairs instead of falling through to the Unknown default.

Adds deriveModule() and deriveMethod() for any unmapped tool names, splitting on underscores and camelCase to produce a reasonable module and method rather than logging Unknown everywhere.

…e for unknowns

Expands TOOL_TO_MODULE with explicit entries for sessions_*, memory_*,
agent_*, and update_plan so these tools resolve to meaningful module/method
pairs instead of falling through to the Unknown default.

Adds deriveModule() and deriveMethod() for any unmapped tool names, splitting
on underscores and camelCase to produce a reasonable module and method rather
than logging Unknown everywhere.
@greptile-apps

greptile-apps Bot commented May 8, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR expands TOOL_TO_MODULE with explicit entries for sessions_*, memory_*, agent_*, and update_plan, and adds deriveModule/deriveMethod fallbacks for any tool not in the static map, replacing the previous Unknown default.

  • Sixteen new static entries give well-known internal tool names meaningful module/method pairs used by scoreIrreversibility, MemoryRiskForecaster, and interceptor.evaluate.
  • deriveModule splits on _, -, ., or camelCase boundaries and capitalises the first segment; deriveMethod camelCases the remainder — but a bug means camelCase input produces a capitalised method name (e.g. "Read" instead of "read"), which can cause policy-engine mismatches in the security-critical interceptor.evaluate call.
  • update_plan is unconditionally routed to Memory.update, coupling plan writes to memory-risk forecasting heuristics without explanation.

Confidence Score: 3/5

The derive fallbacks feed directly into policy-enforcement calls; a capitalization bug in deriveMethod can cause rule mismatches for any unmapped camelCase tool name.

The static TOOL_TO_MODULE additions are correct and safe. The concern is in deriveMethod: splitting a camelCase name like memoryRead yields the method as Read instead of read. If the policy engine or scoreIrreversibility does case-sensitive matching, the wrong rule fires for any unmapped camelCase tool. A one-character fix resolves it, but as written the security-critical evaluation path has a latent case-mismatch defect.

src/plugin/tool-interceptor.ts — specifically the deriveMethod helper and the update_plan mapping.

Important Files Changed

Filename Overview
src/plugin/tool-interceptor.ts Adds 16 static TOOL_TO_MODULE entries and two derive-fallback helpers; deriveMethod emits a capital-first method name for camelCase tool names, which can cause policy mismatches in interceptor.evaluate.

Reviews (1): Last reviewed commit: "feat: add tool mappings for session/memo..." | Re-trigger Greptile

Comment on lines +119 to +122
return parts
.slice(1)
.map((p, i) => (i === 0 ? p : p.charAt(0).toUpperCase() + p.slice(1)))
.join('');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 deriveMethod emits a capital-first-letter method name for camelCase inputs. The regex /(?=[A-Z])/ splits before each uppercase letter but does not lowercase it, so the first element returned by .slice(1) is handed to the i === 0 branch unchanged. deriveMethod("memoryRead")["memory","Read"] → slice(1) = ["Read"] → returns "Read" instead of "read". This method name is passed directly to interceptor.evaluate(moduleName, methodName, ...) for policy enforcement; a case-sensitive policy engine would treat "Read" as an unknown method and apply the wrong (or no) rule.

Suggested change
return parts
.slice(1)
.map((p, i) => (i === 0 ? p : p.charAt(0).toUpperCase() + p.slice(1)))
.join('');
return parts
.slice(1)
.map((p, i) => (i === 0 ? p.charAt(0).toLowerCase() + p.slice(1) : p.charAt(0).toUpperCase() + p.slice(1)))
.join('');

*/
function deriveModule(toolName: string): string {
const first = toolName.split(/[_\-.]|(?=[A-Z])/)[0];
const base = first.replace(/s$/, ''); // plurals: "sessions" → "session"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 deriveModule over-strips any trailing s, not just genuine plurals. The regex .replace(/s$/, '') fires on words like status"Statu", access"Acces", process"Proces". Any future unmapped tool whose first segment ends in a non-plural s would be routed under a mangled module name, silently producing wrong irreversibility scores and incorrect interceptor.evaluate calls.

Suggested change
const base = first.replace(/s$/, ''); // plurals: "sessions" → "session"
const base = first.replace(/(?<=.)s$/, ''); // plurals: "sessions" → "session" (avoid "status"→"statu")

memory_list: { module: 'Memory', method: 'list' },
memory_update: { module: 'Memory', method: 'update' },
memory_delete: { module: 'Memory', method: 'delete' },
update_plan: { module: 'Memory', method: 'update' },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 update_plan routed to Memory.update may trigger unintended memory-risk policies. MemoryRiskForecaster.assess() evaluates the (moduleName, methodName) pair to decide whether to pause and request human approval. Classifying a plan-update as Memory.update means it will be scored against memory-drift and salami-index heuristics designed for raw memory writes, potentially raising false-positive intervention prompts — or, conversely, missing plan-specific risk signals if those are ever added under a Plan module. Is it intentional to map update_plan to Memory.update, or should it have its own Plan module entry to keep memory-risk heuristics scoped correctly?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant