Skip to content

fix: preserve plugin metadata and title in fromPlugin wrapper#18631

Open
Haohao-end wants to merge 1 commit into
anomalyco:devfrom
Haohao-end:fix/12527-preserve-plugin-metadata
Open

fix: preserve plugin metadata and title in fromPlugin wrapper#18631
Haohao-end wants to merge 1 commit into
anomalyco:devfrom
Haohao-end:fix/12527-preserve-plugin-metadata

Conversation

@Haohao-end
Copy link
Copy Markdown

@Haohao-end Haohao-end commented Mar 22, 2026

Issue for this PR

Closes #12527

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

This fixes plugin tool result handling in fromPlugin() so metadata and title set during execution are preserved in the final tool result.

Previously, the wrapper rebuilt the final result with only truncation metadata, which caused metadata set via context.metadata() to be lost. It also treated plugin results as plain strings and dropped structured fields like title and metadata.

This change:

  • preserves the last context.metadata() title/metadata as fallback state
  • supports structured plugin results with output, title, and metadata
  • keeps the legacy string return path for existing plugin tools
  • merges truncation metadata on top of plugin metadata, matching built-in tool behavior

How did you verify your code works?

I verified this locally with:

  • cd ~/opencode-12527/packages/opencode
  • bun test test/tool/registry.test.ts
  • bun run typecheck

I also added regression coverage for:

  • preserving metadata set via context.metadata()
  • preserving structured plugin results
  • preserving legacy string plugin results

Screenshots / recordings

N/A

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@github-actions github-actions Bot added needs:compliance This means the issue will auto-close after 2 hours. and removed needs:compliance This means the issue will auto-close after 2 hours. labels Mar 22, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

@Haohao-end
Copy link
Copy Markdown
Author

All checks are passing now. Happy to make follow-up changes if any feedback comes up.

Copy link
Copy Markdown

@atharvau atharvau left a comment

Choose a reason for hiding this comment

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

Code Review

APPROVED - Important bug fix with comprehensive solution

This PR fixes a significant issue where plugin metadata and titles were being lost during tool execution. The implementation is well-thought-out and includes proper test coverage.

What this PR does well:

  • Comprehensive fix: Addresses metadata loss from both context.metadata() calls and structured plugin returns
  • Backward compatibility: Maintains support for legacy string-only plugin returns
  • Robust error handling: Validates return types and provides clear error messages
  • Excellent test coverage: Three comprehensive test cases cover all scenarios
  • Type safety: Uses proper type guards for runtime validation

Code Quality Assessment:

No Critical Issues Found
No Security Issues Found
No Performance Issues Found

Technical Analysis:

Strengths:

  1. State tracking: Captures metadata state via closure variables (title, meta)
  2. Flexible input handling: Supports both structured objects and plain strings
  3. Proper merging: Truncation metadata correctly overlays plugin metadata
  4. Type validation: Runtime checks ensure safe property access

Architecture:

  • Good: Clean separation between plugin context enhancement and result processing
  • Good: Maintains existing truncation behavior while preserving metadata
  • Good: Error handling guides developers toward correct return format

Code Deep Dive:

// Smart return type detection
const item = plain(result) ? result : undefined
const text = item && typeof item.output === "string" ? item.output : 
             typeof result === "string" ? result : undefined

This logic properly handles both legacy (string) and new (structured) return formats.

Minor Suggestions:

  1. Consider extracting the type guard plain() to a shared utility if used elsewhere
  2. The error message could include the actual return type for better debugging

Test Coverage Analysis:

Excellent test coverage with three scenarios:

  • ✅ Metadata set via context.metadata()
  • ✅ String plugin results (legacy)
  • ✅ Structured plugin results (new format)

All tests properly verify title, output, metadata, and truncation behavior.

Overall Assessment: This is a high-quality fix that resolves a real issue affecting plugin developers. The implementation is robust and well-tested.

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.

fromPlugin wrapper discards custom metadata set by plugin tools via context.metadata()

2 participants