md-to-pdfでローカル画像アップロード機能を追加#38
Conversation
ウォークスルーMarkdown-to-PDF変換機能に画像ファイルのサポートを追加しました。クライアント、CLI、MCPサーバーのAPIシグネチャを更新し、リクエスト形式をJSON形式からマルチパート/フォーム形式に変更。対応するテストとVCRカセットを追加して、画像付きのPDF生成を検証します。 変更内容
推定コードレビュー工数🎯 3 (Moderate) | ⏱️ ~25 minutes 関連する可能性のあるPR
ポエム
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: Organization UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
🧰 Additional context used📓 Path-based instructions (7)**/*.py📄 CodeRabbit inference engine (CLAUDE.md)
Files:
tests/test_*.py📄 CodeRabbit inference engine (CLAUDE.md)
Files:
tests/test_*_vcr.py📄 CodeRabbit inference engine (CLAUDE.md)
Files:
tests/**/*.py📄 CodeRabbit inference engine (CLAUDE.md)
Files:
tests/**/*test*.py📄 CodeRabbit inference engine (tests/CLAUDE.md)
Files:
**/*test*.py📄 CodeRabbit inference engine (.cursor/rules/readme.mdc)
Files:
tests/**/*_vcr.py📄 CodeRabbit inference engine (.cursor/rules/vcr.mdc)
Files:
🧠 Learnings (11)📚 Learning: 2025-12-22T04:35:15.415ZApplied to files:
📚 Learning: 2025-12-22T04:35:29.531ZApplied to files:
📚 Learning: 2025-12-22T04:35:49.634ZApplied to files:
📚 Learning: 2025-12-22T04:35:49.634ZApplied to files:
📚 Learning: 2025-12-22T04:35:15.415ZApplied to files:
📚 Learning: 2025-12-22T04:35:15.415ZApplied to files:
📚 Learning: 2025-12-22T04:35:49.634ZApplied to files:
📚 Learning: 2025-12-22T04:35:06.887ZApplied to files:
📚 Learning: 2025-12-22T04:35:15.415ZApplied to files:
📚 Learning: 2025-12-22T04:35:49.634ZApplied to files:
📚 Learning: 2025-12-22T04:35:29.531ZApplied to files:
🧬 Code graph analysis (1)tests/test_client_vcr.py (3)
🔇 Additional comments (4)
✏️ Tip: You can disable this entire section by setting Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
tests/test_client_vcr.py (1)
48-69: パイプライン失敗の原因:match_onパラメータが必要です。パイプラインエラーログによると、
test_md_to_pdf_with_template_id_vcrでカセットのマッチングに失敗しています。md_to_pdfがフォームベースのエンドポイントに変更されたため、マルチパートリクエストのボディがマッチしません。他の画像アップロードテストと同様に
match_onパラメータを追加するか、カセットを再生成する必要があります。🔧 修正案: match_onパラメータを追加
-@pytest.mark.vcr() +@pytest.mark.vcr(match_on=["method", "scheme", "port", "path", "query"]) def test_md_to_pdf_with_template_id_vcr(client: ToolsClient) -> None:同様に、
test_md_to_pdf_vcr(27行目)にも適用が必要です:-@pytest.mark.vcr() +@pytest.mark.vcr(match_on=["method", "scheme", "port", "path", "query"]) def test_md_to_pdf_vcr(client: ToolsClient) -> None:src/middleman_ai/cli/main.py (1)
46-70: CLI の--imagesオプション実装は正しく実装されています。
click.Path(exists=True)でファイル存在チェックが行われ、multiple=Trueで複数の画像パスを受け入れ、tupleからlistへの変換が適切に行われています。client.md_to_pdfへの引き渡しも正確です。MCPサーバーを
image_pathsパラメータに対応させてください。
src/middleman_ai/client.pyのmd_to_pdfメソッドは既にimage_paths: List[str] | None = Noneパラメータに対応し、ファイル読み込みとMIMEタイプの処理を含めた完全な実装があります。一方、src/middleman_ai/mcp/server.pyのmd_to_pdf関数はimage_pathsパラメータに対応していないため、MCPツールでは画像アップロード機能が利用できません。クライアントとCLIの機能との一貫性を保つために、MCPサーバーを更新する必要があります。
🤖 Fix all issues with AI agents
In `@CHANGELOG.md`:
- Around line 7-14: Update the v0.3.1 header date from 2025-01-15 to 2026-01-15,
move the 「マークダウンから PDF 変換」ローカル画像説明 under a "### 追加" subsection (so both entries
use the same structure), and remove the duplicate "「XLSX → PDF
変換」ツールとの連携(テンプレート解析・変換実行)" line from the v0.3.1 entry because it already exists
in v0.3.0; ensure v0.3.1 now reads with date 2026-01-15, a "### 追加" section
containing only the markdown->PDF local image item, and no duplicated XLSX→PDF
text.
In `@tests/cassettes/test_md_to_pdf_with_template_id_vcr.yaml`:
- Around line 1-46: The pytest VCR decorator on
test_md_to_pdf_with_template_id_vcr must exclude the request body from cassette
matching to avoid "Cannot overwrite existing cassette in 'once' mode"; update
the `@pytest.mark.vcr`() on the test_md_to_pdf_with_template_id_vcr function to
`@pytest.mark.vcr`(match_on=["method", "scheme", "port", "path", "query"]) so VCR
matches only method/scheme/port/path/query and ignores the form body.
🧹 Nitpick comments (2)
src/middleman_ai/client.py (1)
212-223: 拡張子抽出のロバスト性向上を検討現在の
split(".")[-1]は、拡張子のないファイル(例:README)に対してファイル名全体を返します。致命的な問題ではありませんが、os.path.splitextを使用するとより堅牢になります。♻️ より堅牢な拡張子抽出の提案
def _get_image_mime_type(self, filename: str) -> str: """ファイル名から画像のMIMEタイプを推測""" - ext = filename.lower().split(".")[-1] + _, ext = os.path.splitext(filename) + ext = ext.lower().lstrip(".") mime_types = { "png": "image/png", "jpg": "image/jpeg", "jpeg": "image/jpeg", "gif": "image/gif", "webp": "image/webp", "svg": "image/svg+xml", } return mime_types.get(ext, "application/octet-stream")tests/cli/test_cli.py (1)
28-30:--imagesオプションのテストケース追加を推奨
image_paths=Noneのケースはカバーされていますが、--imagesオプションを指定した場合のテストが不足しています。コーディングガイドラインに従い、新しいパラメータに対するテストケースの追加を検討してください。🧪 `--images`オプションのテストケース例
def test_md_to_pdf_cli_with_images(runner, mock_client, tmp_path): """Test md_to_pdf CLI command with images.""" # Create a dummy image file image_path = tmp_path / "test.png" image_path.write_bytes(b"dummy image content") mock_client.md_to_pdf.return_value = "https://example.com/test.pdf" result = runner.invoke( cli, ["md-to-pdf", "--images", str(image_path)], input="# Test with image" ) assert result.exit_code == 0 assert "https://example.com/test.pdf" in result.output mock_client.md_to_pdf.assert_called_once_with( "# Test with image", pdf_template_id=None, image_paths=[str(image_path)] )
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (4)
examples/client_usage/test_image.pngis excluded by!**/*.pngexamples/client_usage/uv.lockis excluded by!**/*.locktests/data/test_image.pngis excluded by!**/*.pngtests/data/テスト画像.pngis excluded by!**/*.png
📒 Files selected for processing (15)
.env.test.sampleCHANGELOG.mdexamples/client_usage/README.mdexamples/client_usage/main.pysrc/middleman_ai/cli/main.pysrc/middleman_ai/client.pysrc/middleman_ai/mcp/server.pytests/cassettes/test_md_to_pdf_vcr.yamltests/cassettes/test_md_to_pdf_with_images_vcr.yamltests/cassettes/test_md_to_pdf_with_japanese_filename_image_vcr.yamltests/cassettes/test_md_to_pdf_with_template_id_vcr.yamltests/cli/test_cli.pytests/test_client.pytests/test_client_vcr.pytests/test_mcp.py
🧰 Additional context used
📓 Path-based instructions (18)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: Use Black formatter with line length of 88 characters for all Python code
Use Ruff linter with specific ruleset for Python code quality checks
Type hints are mandatory and enforced by mypy for all Python code
Files:
src/middleman_ai/mcp/server.pytests/test_client_vcr.pysrc/middleman_ai/client.pytests/cli/test_cli.pysrc/middleman_ai/cli/main.pytests/test_client.pytests/test_mcp.pyexamples/client_usage/main.py
src/middleman_ai/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
src/middleman_ai/**/*.py: Use Pydantic models for all API request and response data definitions
Implement centralized exception handling inexceptions.pywith HTTP status codes mapped to specific exception types
Files:
src/middleman_ai/mcp/server.pysrc/middleman_ai/client.pysrc/middleman_ai/cli/main.py
src/middleman_ai/mcp/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Use FastMCP with
@mcp.tool() decorator for registering tools in MCP server implementation
Files:
src/middleman_ai/mcp/server.py
src/middleman_ai/mcp/*.py
📄 CodeRabbit inference engine (.cursor/rules/mcp.mdc)
src/middleman_ai/mcp/*.py: Each tool must be defined using the@mcp.tool()decorator in MCP server implementation
Function arguments must be explicitly annotated with Python type annotations in MCP tool definitions
Retrieve API key from environment variableMIDDLEMAN_API_KEYduring server startup
Tools with file reading functionality must verify path existence and access permissions before processing
Files:
src/middleman_ai/mcp/server.py
src/middleman_ai/mcp/server.py
📄 CodeRabbit inference engine (.cursor/rules/readme.mdc)
Maintain MCP (Model Context Protocol) implementation in src/middleman_ai/mcp/server.py for AI agent API access
Files:
src/middleman_ai/mcp/server.py
tests/**/*.yaml
📄 CodeRabbit inference engine (.cursor/rules/vcr.mdc)
VCRカセットファイルの手動修正時には、必ず人間(チームメンバーまたは管理者)に修正許可を得てから実施する
Files:
tests/cassettes/test_md_to_pdf_vcr.yamltests/cassettes/test_md_to_pdf_with_japanese_filename_image_vcr.yamltests/cassettes/test_md_to_pdf_with_images_vcr.yamltests/cassettes/test_md_to_pdf_with_template_id_vcr.yaml
{tests/**/*.yaml,vcr_utils.py,conftest.py}
📄 CodeRabbit inference engine (.cursor/rules/vcr.mdc)
VCRカセットファイルに機密情報(APIキーや本番環境以外の環境のURLなど)がフィルタリングされずに記録されていないか確認する。機密情報が記録されていることに気づいた場合、vcr_utils.pyとconftest.pyのフィルタリングロジックを追加し、その旨を理由と共に人間に報告する
Files:
tests/cassettes/test_md_to_pdf_vcr.yamltests/cassettes/test_md_to_pdf_with_japanese_filename_image_vcr.yamltests/cassettes/test_md_to_pdf_with_images_vcr.yamltests/cassettes/test_md_to_pdf_with_template_id_vcr.yaml
tests/test_*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Use pytest-mock for mocking HTTP requests in unit tests to avoid API calls
Files:
tests/test_client_vcr.pytests/test_client.pytests/test_mcp.py
tests/test_*_vcr.py
📄 CodeRabbit inference engine (CLAUDE.md)
Use VCR.py cassettes for integration tests with real API calls, avoiding hard-coded values and using environment variables for sensitive data
Files:
tests/test_client_vcr.py
tests/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Use environment variables for template IDs and sensitive data in test fixtures to ensure environment-independent test assertions
Files:
tests/test_client_vcr.pytests/cli/test_cli.pytests/test_client.pytests/test_mcp.py
tests/**/*test*.py
📄 CodeRabbit inference engine (tests/CLAUDE.md)
tests/**/*test*.py: Test function names for VCR tests must have_vcrsuffix to clearly indicate they are VCR tests
All VCR test functions must be decorated with@pytest.mark.vcr()decorator
For multipart requests involving file uploads, usematch_onparameter in@pytest.mark.vcr()to adjust matching conditions (e.g.,match_on=["method", "scheme", "port", "path", "query"]) since request body varies by environment
Files:
tests/test_client_vcr.pytests/cli/test_cli.pytests/test_client.pytests/test_mcp.py
**/*test*.py
📄 CodeRabbit inference engine (.cursor/rules/readme.mdc)
**/*test*.py: Always run unit tests after implementing changes to verify the implementation is correct
Add or modify test cases when new arguments, parameters, or test perspectives are introduced
Files:
tests/test_client_vcr.pytests/cli/test_cli.pytests/test_client.pytests/test_mcp.py
tests/**/*_vcr.py
📄 CodeRabbit inference engine (.cursor/rules/vcr.mdc)
tests/**/*_vcr.py: VCRテスト関数の命名: 関数名の末尾に_vcrを付けてVCRテストであることを明示する
全てのVCRテスト関数に@pytest.mark.vcr()デコレータを付与する
ファイルアップロードを伴うマルチパートリクエストのテストでは、match_onパラメータを使用してマッチング条件を調整する(例:match_on=["method", "scheme", "port", "path", "query"])
Files:
tests/test_client_vcr.py
src/middleman_ai/client.py
📄 CodeRabbit inference engine (CLAUDE.md)
API authentication requires MIDDLEMAN_API_KEY environment variable; optional MIDDLEMAN_BASE_URL environment variable configures the API endpoint
Maintain Python client code in src/middleman_ai/client.py for simple API access from Python
Files:
src/middleman_ai/client.py
tests/cli/*.py
📄 CodeRabbit inference engine (.cursor/rules/cli.mdc)
tests/cli/*.py: Mock the client component when testing CLI implementations, testing only the CLI code itself
Userunner.invoke()to execute CLI commands in tests, passing standard input via theinputoption parameter
Verify test results by checking exit code, output content, and mock call status
Test error handling cases such as missing API key in CLI tests
Files:
tests/cli/test_cli.py
src/middleman_ai/cli/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Use Click framework for building CLI interface with support for stdin and file argument inputs
Files:
src/middleman_ai/cli/main.py
src/middleman_ai/cli/*.py
📄 CodeRabbit inference engine (.cursor/rules/cli.mdc)
src/middleman_ai/cli/*.py: Each CLI command should be defined with the@cli.command()decorator
Retrieve API key from theMIDDLEMAN_API_KEYenvironment variable
Accept input data from standard input (stdin)
Define command arguments using Click type annotations, paying attention to whether arguments are required or optional
Useclick.ClickExceptionfor error handling in CLI commands
Display progress status usingclick.progressbar
Display user-friendly log messages usingprint()to show what the command is currently doing
The MCP server command is different from other CLI commands in that it starts an MCP server rather than making API calls to Middleman
Files:
src/middleman_ai/cli/main.py
src/middleman_ai/cli/main.py
📄 CodeRabbit inference engine (.cursor/rules/readme.mdc)
Maintain CLI implementation in src/middleman_ai/cli/main.py for command-line API access
Files:
src/middleman_ai/cli/main.py
🧠 Learnings (32)
📚 Learning: 2025-12-22T04:35:41.045Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: .cursor/rules/readme.mdc:0-0
Timestamp: 2025-12-22T04:35:41.045Z
Learning: Applies to src/middleman_ai/mcp/server.py : Maintain MCP (Model Context Protocol) implementation in src/middleman_ai/mcp/server.py for AI agent API access
Applied to files:
src/middleman_ai/mcp/server.py
📚 Learning: 2025-12-22T04:35:34.729Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: .cursor/rules/mcp.mdc:0-0
Timestamp: 2025-12-22T04:35:34.729Z
Learning: Applies to src/middleman_ai/mcp/*.py : Tools with file reading functionality must verify path existence and access permissions before processing
Applied to files:
src/middleman_ai/mcp/server.py
📚 Learning: 2025-12-22T04:35:34.729Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: .cursor/rules/mcp.mdc:0-0
Timestamp: 2025-12-22T04:35:34.729Z
Learning: Applies to src/middleman_ai/mcp/*.py : Each tool must be defined using the `mcp.tool()` decorator in MCP server implementation
Applied to files:
src/middleman_ai/mcp/server.pytests/test_mcp.py
📚 Learning: 2025-12-22T04:35:24.003Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: .cursor/rules/cli.mdc:0-0
Timestamp: 2025-12-22T04:35:24.003Z
Learning: Applies to src/middleman_ai/cli/*.py : The MCP server command is different from other CLI commands in that it starts an MCP server rather than making API calls to Middleman
Applied to files:
src/middleman_ai/mcp/server.py
📚 Learning: 2025-12-22T04:35:34.729Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: .cursor/rules/mcp.mdc:0-0
Timestamp: 2025-12-22T04:35:34.729Z
Learning: Applies to src/middleman_ai/mcp/*.py : Function arguments must be explicitly annotated with Python type annotations in MCP tool definitions
Applied to files:
src/middleman_ai/mcp/server.pytests/test_mcp.py
📚 Learning: 2025-12-22T04:35:49.634Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: .cursor/rules/vcr.mdc:0-0
Timestamp: 2025-12-22T04:35:49.634Z
Learning: Applies to tests/**/*.yaml : VCRカセットファイルの手動修正時には、必ず人間(チームメンバーまたは管理者)に修正許可を得てから実施する
Applied to files:
tests/cassettes/test_md_to_pdf_vcr.yamltests/cassettes/test_md_to_pdf_with_japanese_filename_image_vcr.yamltests/cassettes/test_md_to_pdf_with_images_vcr.yaml
📚 Learning: 2025-12-22T04:35:15.415Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: tests/CLAUDE.md:0-0
Timestamp: 2025-12-22T04:35:15.415Z
Learning: Applies to tests/**/{vcr_utils.py,conftest.py} : Implement filtering of sensitive information (API keys, environment-specific URLs) in cassette files using utilities in `vcr_utils.py` and `conftest.py`, and verify the filtering before reporting results
Applied to files:
tests/cassettes/test_md_to_pdf_vcr.yamltests/cassettes/test_md_to_pdf_with_japanese_filename_image_vcr.yamltests/cassettes/test_md_to_pdf_with_images_vcr.yamltests/test_client_vcr.py
📚 Learning: 2025-12-22T04:35:06.887Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-22T04:35:06.887Z
Learning: Applies to tests/test_*_vcr.py : Use VCR.py cassettes for integration tests with real API calls, avoiding hard-coded values and using environment variables for sensitive data
Applied to files:
tests/cassettes/test_md_to_pdf_vcr.yamltests/cassettes/test_md_to_pdf_with_japanese_filename_image_vcr.yamltests/cassettes/test_md_to_pdf_with_images_vcr.yamltests/test_client_vcr.py
📚 Learning: 2025-12-22T04:35:15.415Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: tests/CLAUDE.md:0-0
Timestamp: 2025-12-22T04:35:15.415Z
Learning: Before reporting VCR test results, verify that sensitive information (API keys, etc.) is properly filtered from cassette files using tools like grep
Applied to files:
tests/cassettes/test_md_to_pdf_vcr.yamltests/cassettes/test_md_to_pdf_with_japanese_filename_image_vcr.yamltests/cassettes/test_md_to_pdf_with_images_vcr.yaml
📚 Learning: 2025-12-22T04:35:15.415Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: tests/CLAUDE.md:0-0
Timestamp: 2025-12-22T04:35:15.415Z
Learning: Applies to tests/**/*test*.py : For multipart requests involving file uploads, use `match_on` parameter in `pytest.mark.vcr()` to adjust matching conditions (e.g., `match_on=["method", "scheme", "port", "path", "query"]`) since request body varies by environment
Applied to files:
tests/cassettes/test_md_to_pdf_vcr.yamltests/cassettes/test_md_to_pdf_with_images_vcr.yamltests/test_client_vcr.py
📚 Learning: 2025-12-22T04:35:49.634Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: .cursor/rules/vcr.mdc:0-0
Timestamp: 2025-12-22T04:35:49.634Z
Learning: ローカル環境でのVCRテスト実行時に、実際のリクエストの内容がカセットに記録されたリクエストの内容と一致するか確認される。一致する場合のみ記録された応答が返される
Applied to files:
tests/cassettes/test_md_to_pdf_vcr.yamltests/cassettes/test_md_to_pdf_with_japanese_filename_image_vcr.yamltests/cassettes/test_md_to_pdf_with_images_vcr.yaml
📚 Learning: 2025-12-22T04:35:49.634Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: .cursor/rules/vcr.mdc:0-0
Timestamp: 2025-12-22T04:35:49.634Z
Learning: Applies to {tests/**/*.yaml,vcr_utils.py,conftest.py} : VCRカセットファイルに機密情報(APIキーや本番環境以外の環境のURLなど)がフィルタリングされずに記録されていないか確認する。機密情報が記録されていることに気づいた場合、vcr_utils.pyとconftest.pyのフィルタリングロジックを追加し、その旨を理由と共に人間に報告する
Applied to files:
tests/cassettes/test_md_to_pdf_vcr.yamltests/cassettes/test_md_to_pdf_with_japanese_filename_image_vcr.yamltests/cassettes/test_md_to_pdf_with_images_vcr.yamltests/test_client_vcr.py
📚 Learning: 2025-12-22T04:35:49.634Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: .cursor/rules/vcr.mdc:0-0
Timestamp: 2025-12-22T04:35:49.634Z
Learning: Applies to tests/**/*_vcr.py : VCRテスト関数の命名: 関数名の末尾に `_vcr` を付けてVCRテストであることを明示する
Applied to files:
tests/cassettes/test_md_to_pdf_with_japanese_filename_image_vcr.yamltests/cassettes/test_md_to_pdf_with_images_vcr.yamltests/test_client_vcr.py
📚 Learning: 2025-12-22T04:35:15.415Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: tests/CLAUDE.md:0-0
Timestamp: 2025-12-22T04:35:15.415Z
Learning: Cassette files must not be manually modified without explicit approval from a team member or administrator to maintain test reliability
Applied to files:
tests/cassettes/test_md_to_pdf_with_images_vcr.yaml
📚 Learning: 2025-12-22T04:35:49.634Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: .cursor/rules/vcr.mdc:0-0
Timestamp: 2025-12-22T04:35:49.634Z
Learning: Applies to tests/**/*_vcr.py : ファイルアップロードを伴うマルチパートリクエストのテストでは、`match_on` パラメータを使用してマッチング条件を調整する(例:`match_on=["method", "scheme", "port", "path", "query"]`)
Applied to files:
tests/cassettes/test_md_to_pdf_with_images_vcr.yamltests/test_client_vcr.py
📚 Learning: 2025-12-22T04:35:06.887Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-22T04:35:06.887Z
Learning: Applies to tests/**/*.py : Use environment variables for template IDs and sensitive data in test fixtures to ensure environment-independent test assertions
Applied to files:
.env.test.sample
📚 Learning: 2025-12-22T04:35:06.887Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-22T04:35:06.887Z
Learning: Applies to src/middleman_ai/client.py : API authentication requires MIDDLEMAN_API_KEY environment variable; optional MIDDLEMAN_BASE_URL environment variable configures the API endpoint
Applied to files:
.env.test.sampleexamples/client_usage/main.py
📚 Learning: 2025-12-22T04:35:24.003Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: .cursor/rules/cli.mdc:0-0
Timestamp: 2025-12-22T04:35:24.003Z
Learning: Applies to src/middleman_ai/cli/*.py : Retrieve API key from the `MIDDLEMAN_API_KEY` environment variable
Applied to files:
.env.test.sample
📚 Learning: 2025-12-22T04:35:29.531Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: .cursor/rules/client.mdc:0-0
Timestamp: 2025-12-22T04:35:29.531Z
Learning: Applies to test_client_vcr.py : In VCR tests, use environment-independent assertions for values that may differ across invocations, such as checking URL prefixes or substrings rather than exact matches
Applied to files:
tests/test_client_vcr.py
📚 Learning: 2025-12-22T04:35:49.634Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: .cursor/rules/vcr.mdc:0-0
Timestamp: 2025-12-22T04:35:49.634Z
Learning: Applies to tests/**/*_vcr.py : 全てのVCRテスト関数に `pytest.mark.vcr()` デコレータを付与する
Applied to files:
tests/test_client_vcr.py
📚 Learning: 2025-12-22T04:35:15.415Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: tests/CLAUDE.md:0-0
Timestamp: 2025-12-22T04:35:15.415Z
Learning: Applies to tests/**/*test*.py : Test function names for VCR tests must have `_vcr` suffix to clearly indicate they are VCR tests
Applied to files:
tests/test_client_vcr.py
📚 Learning: 2025-12-22T04:35:15.415Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: tests/CLAUDE.md:0-0
Timestamp: 2025-12-22T04:35:15.415Z
Learning: Applies to tests/**/*test*.py : All VCR test functions must be decorated with `pytest.mark.vcr()` decorator
Applied to files:
tests/test_client_vcr.py
📚 Learning: 2025-12-22T04:35:29.531Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: .cursor/rules/client.mdc:0-0
Timestamp: 2025-12-22T04:35:29.531Z
Learning: Applies to test_client.py : In test_client.py, use pytest with mocking to test only the client code, not API calls, with separate test cases for success/failure scenarios and different parameter patterns
Applied to files:
tests/test_client_vcr.pytests/cli/test_cli.pytests/test_client.py
📚 Learning: 2025-12-22T04:35:41.045Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: .cursor/rules/readme.mdc:0-0
Timestamp: 2025-12-22T04:35:41.045Z
Learning: Applies to src/middleman_ai/cli/main.py : Maintain CLI implementation in src/middleman_ai/cli/main.py for command-line API access
Applied to files:
src/middleman_ai/client.pysrc/middleman_ai/cli/main.pyexamples/client_usage/main.py
📚 Learning: 2025-12-22T04:35:24.003Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: .cursor/rules/cli.mdc:0-0
Timestamp: 2025-12-22T04:35:24.003Z
Learning: Applies to tests/cli/*.py : Use `runner.invoke()` to execute CLI commands in tests, passing standard input via the `input` option parameter
Applied to files:
tests/cli/test_cli.py
📚 Learning: 2025-12-22T04:35:24.003Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: .cursor/rules/cli.mdc:0-0
Timestamp: 2025-12-22T04:35:24.003Z
Learning: Applies to tests/cli/*.py : Verify test results by checking exit code, output content, and mock call status
Applied to files:
tests/cli/test_cli.pytests/test_client.py
📚 Learning: 2025-12-22T04:35:24.003Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: .cursor/rules/cli.mdc:0-0
Timestamp: 2025-12-22T04:35:24.003Z
Learning: Applies to tests/cli/*.py : Mock the client component when testing CLI implementations, testing only the CLI code itself
Applied to files:
tests/cli/test_cli.pytests/test_client.py
📚 Learning: 2025-12-22T04:35:06.887Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-22T04:35:06.887Z
Learning: Applies to tests/test_*.py : Use pytest-mock for mocking HTTP requests in unit tests to avoid API calls
Applied to files:
tests/test_client.py
📚 Learning: 2025-12-22T04:35:34.729Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: .cursor/rules/mcp.mdc:0-0
Timestamp: 2025-12-22T04:35:34.729Z
Learning: Applies to {test_mcp.py,test_mcp_cli.py} : Mock client processing in MCP tests and only test MCP implementation details
Applied to files:
tests/test_client.pytests/test_mcp.py
📚 Learning: 2025-12-22T04:35:41.045Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: .cursor/rules/readme.mdc:0-0
Timestamp: 2025-12-22T04:35:41.045Z
Learning: Applies to **/*test*.py : Add or modify test cases when new arguments, parameters, or test perspectives are introduced
Applied to files:
tests/test_mcp.py
📚 Learning: 2025-12-22T04:35:06.887Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-22T04:35:06.887Z
Learning: Applies to src/middleman_ai/mcp/**/*.py : Use FastMCP with mcp.tool() decorator for registering tools in MCP server implementation
Applied to files:
tests/test_mcp.py
📚 Learning: 2025-12-22T04:35:41.045Z
Learnt from: CR
Repo: GenerativeAgents/middleman-sdk PR: 0
File: .cursor/rules/readme.mdc:0-0
Timestamp: 2025-12-22T04:35:41.045Z
Learning: Applies to src/middleman_ai/client.py : Maintain Python client code in src/middleman_ai/client.py for simple API access from Python
Applied to files:
examples/client_usage/main.py
🧬 Code graph analysis (6)
src/middleman_ai/mcp/server.py (2)
src/middleman_ai/cli/main.py (1)
md_to_pdf(53-80)src/middleman_ai/client.py (1)
md_to_pdf(158-210)
tests/test_client_vcr.py (4)
tests/test_client.py (1)
client(32-34)src/middleman_ai/client.py (2)
ToolsClient(71-607)md_to_pdf(158-210)src/middleman_ai/cli/main.py (1)
md_to_pdf(53-80)src/middleman_ai/mcp/server.py (1)
md_to_pdf(26-38)
src/middleman_ai/client.py (4)
src/middleman_ai/cli/main.py (1)
md_to_pdf(53-80)src/middleman_ai/mcp/server.py (1)
md_to_pdf(26-38)src/middleman_ai/models.py (1)
MdToPdfResponse(8-14)src/middleman_ai/exceptions.py (2)
ValidationError(42-43)ConnectionError(38-39)
tests/cli/test_cli.py (4)
tests/cli/conftest.py (1)
mock_client(16-21)src/middleman_ai/cli/main.py (1)
md_to_pdf(53-80)src/middleman_ai/client.py (1)
md_to_pdf(158-210)src/middleman_ai/mcp/server.py (1)
md_to_pdf(26-38)
src/middleman_ai/cli/main.py (2)
src/middleman_ai/client.py (1)
md_to_pdf(158-210)src/middleman_ai/mcp/server.py (1)
md_to_pdf(26-38)
examples/client_usage/main.py (3)
src/middleman_ai/client.py (2)
ToolsClient(71-607)md_to_pdf(158-210)tests/test_client.py (1)
client(32-34)tests/test_client_vcr.py (1)
client(15-24)
🪛 GitHub Actions: Run Tests
tests/test_client_vcr.py
[error] 1-1: vcr CannotOverwriteExistingCassetteException: Can't overwrite existing cassette ('/home/runner/work/middleman-sdk/middleman-sdk/tests/cassettes/test_md_to_pdf_with_template_id_vcr.yaml') in your current record mode ('once'). No match for the request (POST https://middleman-ai.com/api/v1/tools/md-to-pdf/form). Matchers succeeded: ['method', 'path', 'query']; body assertion failure.
tests/cassettes/test_md_to_pdf_with_template_id_vcr.yaml
[error] 1-1: VCR cassette write error: Cannot overwrite existing cassette in 'once' mode. Received request body does not match recorded cassette body.
🔇 Additional comments (17)
.env.test.sample (1)
5-5: LGTM! テスト用環境変数の追加が適切です。XLSX テンプレート ID 用の環境変数が追加されており、既存の PDF や PPTX テンプレート ID と同じ命名規則とフォーマットに従っています。テストフィクスチャでテンプレート ID に環境変数を使用するというベストプラクティスにも沿っています。
Based on learnings, this follows the established pattern of using environment variables for template IDs in test fixtures.
examples/client_usage/README.md (1)
18-18: LGTM!新しいXLSX → PDF機能に対応する環境変数のドキュメントが追加されており、既存のテンプレートID設定のパターンと一致しています。
src/middleman_ai/client.py (1)
158-210: LGTM!
image_pathsパラメータの追加とマルチパートフォームデータの処理が適切に実装されています。既存のpdf_to_page_imagesやpptx_to_page_imagesメソッドと同様のパターン(Content-Typeヘッダーの削除、requests.postの直接使用)に従っており、一貫性が保たれています。エラーハンドリング(
OSError、PydanticValidationError、RequestException)も適切にカバーされています。examples/client_usage/main.py (2)
88-100: LGTM!XLSX → PDFの例が適切に実装されています。環境変数の存在チェックによる条件分岐と、未設定時のスキップメッセージは良いパターンです。他のテンプレート依存の例(JSON → PPTXなど)にも同様のパターンを適用することを検討してもよいかもしれません。
23-26: 検証結果:このレビューコメントは不正確です
test_image.pngはリポジトリに存在します(examples/client_usage/test_image.png、284バイト)。したがって、ライン23-26のサンプルコードは正常に動作し、ファイルが見つからないエラーは発生しません。修正は必要ありません。Likely an incorrect or invalid review comment.
tests/test_mcp.py (1)
86-91: LGTM! テストカバレッジの拡充を検討既存のテストが新しい
image_pathsパラメータに対応するよう更新されています。今後、
image_pathsが指定された場合のテストケースを追加することで、画像パス検証ロジック(md_file_to_pdfの画像ファイル存在チェック等)のカバレッジを向上できます。コーディングガイドラインに基づき、新しいパラメータが導入された際にはテストケースの追加を検討してください。tests/cli/test_cli.py (1)
18-20: LGTM!CLIテストが新しい
image_pathsパラメータに対応するよう更新されています。tests/cassettes/test_md_to_pdf_with_japanese_filename_image_vcr.yaml (1)
1-60: 機密情報のフィルタリングが適切に行われています。VCRカセットファイルを確認しました:
authorizationヘッダーがDUMMYにフィルタリングされている- レスポンスヘッダー(
date,server,set-cookie,x-middleware-rewrite,x-request-id)が適切にFILTEREDされている- 機密情報の漏洩は見られません
tests/cassettes/test_md_to_pdf_with_images_vcr.yaml (1)
1-58: 機密情報のフィルタリングが適切に行われています。VCRカセットファイルを確認しました:
authorizationヘッダーがDUMMYにフィルタリングされている- レスポンスヘッダーが適切に
FILTEREDされている- 機密情報の漏洩は見られません
tests/test_client_vcr.py (1)
340-381: 画像アップロードテストの実装が適切です。
_vcrサフィックスによる命名規則に準拠@pytest.mark.vcr(match_on=[...])でマルチパートリクエストのボディをマッチング対象外に設定(コーディングガイドラインに準拠)- 環境非依存のアサーション(URLプレフィックスとサブストリングのチェック)を使用
tests/test_client.py (3)
59-69: フォームベースAPIへのモック変更が適切です。
requests.postへの直接モックは、client.pyの実装変更(md_to_pdfがrequests.postを直接使用)と整合しています。アサーションでフォームデータ構造(data["markdown"]、files、timeout)を適切に検証しています。
76-91: テンプレートID付きテストが適切に更新されています。フォームデータに
pdf_template_idが正しく含まれていることを検証しています。
113-157: エラーハンドリングテストの更新が適切です。
_handle_responseメソッドが必要とする追加の属性(url、headers、text)がモックに設定されており、requests.postへの変更も一貫しています。src/middleman_ai/mcp/server.py (3)
42-46: 関数シグネチャとドキュメントは適切に更新されています。
image_pathsパラメータが正しく型アノテーション付きで追加され、docstringも更新されています。コーディングガイドラインに従い、MCP ツール定義で引数が明示的に型アノテーションされています。
68-76: 画像パス検証ロジックは適切に実装されています。コーディングガイドラインに従い、ファイル読み取り機能を持つツールは処理前にパスの存在とアクセス権限を検証しています。検証は既存の md ファイル検証パターンと一貫しており、適切なエラーメッセージが提供されています。
78-82: クライアント呼び出しは正しく更新されています。
client.md_to_pdfへの呼び出しがimage_pathsパラメータを含むように正しく更新されており、src/middleman_ai/client.pyのクライアント API シグネチャと一致しています。tests/cassettes/test_md_to_pdf_vcr.yaml (1)
1-46: VCR カセットファイルは適切にフィルタリングされています。機密情報(
authorization、date、server、set-cookie、x-middleware-rewrite、x-request-id)が適切にフィルタリングされていることを確認しました。フォームベースのエンドポイント(/api/v1/tools/md-to-pdf/form)への変更が正しく反映されています。
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
Summary by CodeRabbit
リリースノート
新機能
ドキュメント
テスト
✏️ Tip: You can customize this high-level summary in your review settings.