Skip to content

Conversation

TejasGhatte
Copy link
Collaborator

@TejasGhatte TejasGhatte commented Sep 26, 2025

Summary

Improve semantic cache consistency by normalizing tool order in request parameters before hashing.

Changes

  • Added a new normalizeParamsForHashing function that sorts tools by function name before hashing
  • Modified generateRequestHash to use the normalized parameters
  • This ensures that requests with identical tools in different orders will produce the same hash and properly hit the cache

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (Next.js)
  • Docs

How to test

  1. Create two identical requests with tools in different orders
  2. Verify both requests generate the same hash and hit the cache
# Core/Transports
go version
go test ./...

Breaking changes

  • Yes
  • No

Related issues

Fixes inconsistent cache hits when tools are provided in different orders.

Security considerations

No security implications as this only affects internal hash generation.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

Copy link
Contributor

coderabbitai bot commented Sep 26, 2025

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • Ensures consistent caching for requests with multiple tools by ignoring tool order, reducing unexpected cache misses.
  • Performance

    • Improves cache hit rate and responsiveness by normalizing parameters before hashing.

Walkthrough

Adds a parameter normalization step for hashing by sorting tools in model parameters, integrates it into request hash generation, updates imports, and adjusts a comment accordingly.

Changes

Cohort / File(s) Summary
Semantic cache hashing normalization
plugins/semanticcache/utils.go
Added normalizeParamsForHashing to sort tools by function name when multiple tools are present; generateRequestHash now hashes normalized params; imported sort; updated comment to reflect normalization.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Caller
  participant Plugin
  participant Normalizer as normalizeParamsForHashing
  participant Hasher as Hash Generator

  Caller->>Plugin: generateRequestHash(req)
  Plugin->>Normalizer: Normalize req.Params (sort tools by function name)
  alt Params is nil or ≤1 tool
    Normalizer-->>Plugin: Return original/unchanged params
  else Multiple tools
    Normalizer-->>Plugin: Return params with tools sorted
  end
  Plugin->>Hasher: Compute hash over normalized params + other inputs
  Hasher-->>Plugin: Hash value
  Plugin-->>Caller: Return request hash
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

In caches where the hashes spin,
I sort my tools, then dive right in.
Deterministic nibble, nibble—neat,
No shuffled wrenches at my feet.
With ordered paws and steady dash,
This bunny seals a solid hash. 🐇🔧

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly describes the main change—sorting tools alphabetically during hash generation—and clearly indicates that it is a fix, matching the implementation of normalizeParamsForHashing and its use in generateRequestHash.
Description Check ✅ Passed The pull request description closely follows the repository template by providing a clear summary, detailed changes, type of change, affected areas, testing instructions, breaking changes, related issues, security considerations, and a completed checklist, with only optional screenshot content omitted since it is not applicable.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 09-26-fix_sort_tools_alphabetically_while_generating_hash

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Collaborator Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@TejasGhatte TejasGhatte marked this pull request as ready for review September 26, 2025 10:05
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 46cdc22 and 86567d3.

📒 Files selected for processing (1)
  • plugins/semanticcache/utils.go (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
plugins/semanticcache/utils.go (1)
core/schemas/bifrost.go (4)
  • RequestInput (117-123)
  • ModelParameters (295-312)
  • Tool (331-335)
  • Function (324-328)

Comment on lines +484 to +486
sort.Slice(sortedTools, func(i, j int) bool {
return sortedTools[i].Function.Name < sortedTools[j].Function.Name
})
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Ensure the sort canonicalizes tools with identical names

Line [485] compares only Function.Name. When two requests carry the same set of tools but the tools share a name (common for different versions of the same function), the comparator treats them as equal and leaves their original order untouched. That means requests ["foo(v1)", "foo(v2)"] and ["foo(v2)", "foo(v1)"] still hash differently, so the cache remains inconsistent for precisely the class of collisions we’re trying to fix. Please introduce deterministic tie-breakers (e.g., fall back to type/ID and a serialized representation of the tool) so equal-name tools always end up in the same order.

You can address it like this:

-	sort.Slice(sortedTools, func(i, j int) bool {
-		return sortedTools[i].Function.Name < sortedTools[j].Function.Name
-	})
+	sort.Slice(sortedTools, func(i, j int) bool {
+		left := sortedTools[i]
+		right := sortedTools[j]
+
+		if left.Function.Name != right.Function.Name {
+			return left.Function.Name < right.Function.Name
+		}
+		if left.Type != right.Type {
+			return left.Type < right.Type
+		}
+		if (left.ID != nil) != (right.ID != nil) {
+			return left.ID != nil
+		}
+		if left.ID != nil && right.ID != nil && *left.ID != *right.ID {
+			return *left.ID < *right.ID
+		}
+
+		leftKey, _ := json.Marshal(left)
+		rightKey, _ := json.Marshal(right)
+		return string(leftKey) < string(rightKey)
+	})
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
sort.Slice(sortedTools, func(i, j int) bool {
return sortedTools[i].Function.Name < sortedTools[j].Function.Name
})
sort.Slice(sortedTools, func(i, j int) bool {
left := sortedTools[i]
right := sortedTools[j]
if left.Function.Name != right.Function.Name {
return left.Function.Name < right.Function.Name
}
if left.Type != right.Type {
return left.Type < right.Type
}
if (left.ID != nil) != (right.ID != nil) {
return left.ID != nil
}
if left.ID != nil && right.ID != nil && *left.ID != *right.ID {
return *left.ID < *right.ID
}
leftKey, _ := json.Marshal(left)
rightKey, _ := json.Marshal(right)
return string(leftKey) < string(rightKey)
})
🤖 Prompt for AI Agents
In plugins/semanticcache/utils.go around lines 484-486, the sort comparator only
compares Function.Name which leaves tools with identical names in their original
(non-deterministic) order; update the comparator to canonicalize ties by
performing deterministic fallbacks: first compare Function.Name, then
Function.Type (or Go type), then a stable Function.ID (if present), and finally
a serialized representation (e.g., JSON or a stable string) of the tool/function
as the last tie-breaker so tools with the same name always sort the same way
across requests.

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