diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index efa76ab..c87227c 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,27 +1,30 @@ { - "name": "Google-Patent-CLI Dev", - "build": { - "dockerfile": "Dockerfile", - "context": ".." - }, - "features": { - "ghcr.io/devcontainers/features/common-utils:2": { - "installZsh": "true", - "username": "vscode", - "userUid": "1000", - "userGid": "1000", - "upgradePackages": "false" - }, - "ghcr.io/devcontainers/features/github-cli:1": {}, - "ghcr.io/devcontainers/features/git:1": {} - }, - "customizations": { - "vscode": {} - }, - "containerEnv": { - "Z_AI_API_KEY": "${localEnv:Z_AI_API_KEY}", - "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1" - }, - "postCreateCommand": "bash .devcontainer/post-create.sh", - "remoteUser": "vscode" -} \ No newline at end of file + "name": "Google-Patent-CLI Dev", + "build": { + "dockerfile": "Dockerfile", + "context": "..", + }, + "features": { + "ghcr.io/devcontainers/features/common-utils:2": { + "installZsh": "true", + "username": "vscode", + "userUid": "1000", + "userGid": "1000", + "upgradePackages": "false", + }, + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers/features/git:1": {}, + }, + "mounts": [ + "source=${localEnv:HOME}/.config/gh,target=/home/vscode/.config/gh,type=bind,consistency=cached", + ], + "customizations": { + "vscode": {}, + }, + "containerEnv": { + "Z_AI_API_KEY": "${localEnv:Z_AI_API_KEY}", + "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1", + }, + "postCreateCommand": "bash .devcontainer/post-create.sh", + "remoteUser": "vscode", +} diff --git a/.devcontainer/post-create.sh b/.devcontainer/post-create.sh index 579be7d..83f40bf 100644 --- a/.devcontainer/post-create.sh +++ b/.devcontainer/post-create.sh @@ -41,6 +41,14 @@ EOF echo 'eval "$(mise activate bash)"' >> $HOME/.bashrc echo 'eval "$(mise activate zsh)"' >> $HOME/.zshrc + # Install skill-bench + if ! command -v skill-bench >/dev/null 2>&1; then + echo "[Devcontainer Setup] Installing skill-bench..." + curl -fsSL https://raw.githubusercontent.com/sonesuke/skill-bench/main/scripts/setup.sh | sh + else + echo "[Devcontainer Setup] skill-bench already installed: $(skill-bench --version 2>/dev/null || echo 'unknown')" + fi + # Configure google-patent-cli to use chromium # Note: chrome_args will be dynamically determined by the app echo "[Devcontainer Setup] Configuring google-patent-cli..." diff --git a/.gitignore b/.gitignore index 112eb9c..b0483ba 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ debug_page.html patent_page_dom.html .claude/worktrees/ +logs/ +.skill-bench/ diff --git a/Cargo.lock b/Cargo.lock index cfea5e2..49027fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -612,7 +612,7 @@ dependencies = [ [[package]] name = "google-patent-cli" -version = "0.1.6" +version = "0.2.0" dependencies = [ "anyhow", "assert_cmd", diff --git a/mise.toml b/mise.toml index 68ebdee..3db2e03 100644 --- a/mise.toml +++ b/mise.toml @@ -11,7 +11,7 @@ run = "RUSTFLAGS=\"-D warnings\" cargo test --all-targets" depends = ["fmt", "clippy", "test"] [tasks.skill-test] -run = "skill-bench run tests --plugin-dir claude-plugin --log logs" +run = "cargo install --path . && skill-bench run tests --plugin-dir claude-plugin --log logs" [tasks.skill-test-list] run = "skill-bench list tests" diff --git a/src/mcp/mod.rs b/src/mcp/mod.rs index 884cd62..f96cc4e 100644 --- a/src/mcp/mod.rs +++ b/src/mcp/mod.rs @@ -14,6 +14,7 @@ use rmcp::{ }; use serde::{Deserialize, Serialize}; use serde_json::Value; +use serde_json::json; use std::collections::HashMap; use std::hash::{DefaultHasher, Hash, Hasher}; use std::sync::Arc; @@ -231,11 +232,27 @@ impl PatentHandler { json: &Value, root_label: Option<&str>, ) -> Option { - let engine = if let Some(label) = root_label { - CypherEngine::from_json_auto_as_root_with_label(json, label).ok()? + // Try to create engine from the provided JSON + let engine_result = if let Some(label) = root_label { + CypherEngine::from_json_auto_as_root_with_label(json, label) } else { - CypherEngine::from_json_auto(json).ok()? + CypherEngine::from_json_auto(json) }; + + let engine = match engine_result { + Ok(e) => e, + Err(_) => { + // If failed (e.g., empty results), create a minimal valid graph + // Create a dummy node that CypherEngine can parse + let fallback_json = if let Some(label) = root_label { + json!({ label: [{"id": "_dummy", "_label": label }] }) + } else { + json!({ "Patent": [{"id": "_dummy", "title": "", "url": ""}] }) + }; + CypherEngine::from_json_auto(&fallback_json).ok()? + } + }; + let graph_schema = engine.get_schema(); // Store the engine diff --git a/tests/patent-assignee-check/triggering.toml b/tests/patent-assignee-check/triggering.toml index 15e6b8a..0ced2b3 100644 --- a/tests/patent-assignee-check/triggering.toml +++ b/tests/patent-assignee-check/triggering.toml @@ -2,7 +2,7 @@ name = "triggering" description = "Verify patent-assignee-check skill is triggered when checking assignee variations" -timeout = 120 +timeout = 300 test_prompt = """ I want to verify the correct assignee name for "Salesforce" in patent databases. diff --git a/tests/patent-search/functional-empty.toml b/tests/patent-search/functional-empty.toml new file mode 100644 index 0000000..e050a2e --- /dev/null +++ b/tests/patent-search/functional-empty.toml @@ -0,0 +1,30 @@ +# Test Case: Patent Search - Empty Results + +name = "functional-empty" +description = "Verify patent-search skill handles empty search results correctly" +timeout = 120 + +test_prompt = """ +Search for patents with query "xyz-nonexistent-patent-123" and limit 5. +Then use execute_cypher to query the dataset. +""" + +[[checks]] +name = "mcp_server_loaded" +command = { command = "mcp-loaded", server = "google-patent-cli" } + +[[checks]] +name = "skill_loaded" +command = { command = "skill-loaded", skill = "patent-search" } + +[[checks]] +name = "patent_search_skill_invoked" +command = { command = "skill-invoked", skill = "patent-search" } + +[[checks]] +name = "search_patents_mcp_called" +command = { command = "mcp-success", tool = "search_patents" } + +[[checks]] +name = "execute_cypher_mcp_called" +command = { command = "mcp-success", tool = "execute_cypher" }