reverse-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
21
research-what-we-did/Deep-Research-skills/LICENSE
Normal file
21
research-what-we-did/Deep-Research-skills/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Lan Zheng
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
170
research-what-we-did/Deep-Research-skills/README.md
Normal file
170
research-what-we-did/Deep-Research-skills/README.md
Normal file
@@ -0,0 +1,170 @@
|
||||
# Deep Research Skill for Claude Code / OpenCode / Codex
|
||||
|
||||
[English](README.md) | [中文](README.zh.md)
|
||||
|
||||
> If you find this project helpful, please give it a star! :star:
|
||||
|
||||
> Inspired by [RhinoInsight: Improving Deep Research through Control Mechanisms for Model Behavior and Context](https://arxiv.org/abs/2511.18743)
|
||||
|
||||
A structured research workflow skill for Claude Code, OpenCode, and Codex, supporting two-phase research: outline generation (extensible) and deep investigation. Human-in-the-loop design ensures precise control at every stage.
|
||||
|
||||

|
||||
|
||||
## Use Cases
|
||||
|
||||
- **Academic Research**: Paper surveys, benchmark reviews, literature analysis
|
||||
- **Technical Research**: Technology comparison, framework evaluation, tool selection
|
||||
- **Market Research**: Competitor analysis, industry trends, product comparison
|
||||
- **Due Diligence**: Company research, investment analysis, risk assessment
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Weizhena/deep-research-skills.git
|
||||
cd deep-research-skills
|
||||
```
|
||||
|
||||
### Claude Code
|
||||
```bash
|
||||
# English version
|
||||
cp -r skills/research-en/* ~/.claude/skills/
|
||||
|
||||
# Chinese version
|
||||
cp -r skills/research-zh/* ~/.claude/skills/
|
||||
|
||||
# Required: Install agent and modules
|
||||
cp agents/web-search-agent.md ~/.claude/agents/
|
||||
cp -r agents/web-search-modules ~/.claude/agents/
|
||||
|
||||
# Required: Install Python dependency
|
||||
pip install pyyaml
|
||||
```
|
||||
|
||||
### OpenCode (default: gpt-5.4)
|
||||
```bash
|
||||
# Skills (same as Claude Code)
|
||||
cp -r skills/research-en/* ~/.claude/skills/ # or research-zh for Chinese
|
||||
|
||||
# Required: Enable web search for current shell
|
||||
export OPENCODE_ENABLE_EXA=1
|
||||
|
||||
# Optional: make it permanent
|
||||
echo 'export OPENCODE_ENABLE_EXA=1' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
|
||||
# Required: Install agent and modules
|
||||
cp agents/web-search-opencode.md ~/.config/opencode/agents/web-search.md
|
||||
cp -r agents/web-search-modules ~/.config/opencode/agents/
|
||||
|
||||
# Required: Install Python dependency
|
||||
pip install pyyaml
|
||||
```
|
||||
|
||||
> **Important**: In OpenCode, ANY model's websearch requires `OPENCODE_ENABLE_EXA=1`. A plain `export` only affects the current shell; writing it to `~/.bashrc` makes it persistent. Without it, you only get `web fetch`, which is weaker for the deep research phase.
|
||||
|
||||
### Codex
|
||||
```bash
|
||||
# English version
|
||||
mkdir -p ~/.codex/skills ~/.codex/agents
|
||||
cp -r skills/research-codex-en/* ~/.codex/skills/
|
||||
|
||||
# Chinese version
|
||||
mkdir -p ~/.codex/skills ~/.codex/agents
|
||||
cp -r skills/research-codex-zh/* ~/.codex/skills/
|
||||
|
||||
# Required: Install web researcher agent and modules
|
||||
cp agents-codex/web-researcher.toml ~/.codex/agents/
|
||||
cp -r agents-codex/web-search-modules ~/.codex/agents/
|
||||
|
||||
# Required: Install Python dependency
|
||||
pip install pyyaml
|
||||
```
|
||||
|
||||
Add or update `~/.codex/config.toml` using either method below:
|
||||
|
||||
**Option A: Automatic script**
|
||||
|
||||
```bash
|
||||
cd deep-research-skills
|
||||
bash scripts/install-codex.sh
|
||||
```
|
||||
|
||||
**Option B: Manual edit**
|
||||
|
||||
```toml
|
||||
suppress_unstable_features_warning = true
|
||||
|
||||
[features]
|
||||
multi_agent = true
|
||||
default_mode_request_user_input = true
|
||||
|
||||
[agents.web_researcher]
|
||||
description = "Use this agent when you need to research information on the internet, particularly for debugging issues, finding solutions to technical problems, or gathering comprehensive information from multiple sources. This agent excels at finding relevant discussions. Use when you need creative search strategies, thorough investigation, or compilation of findings from multiple sources."
|
||||
config_file = "agents/web-researcher.toml"
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
> **Claude Code 2.1.0+**: Direct `/skill-name` trigger is now supported!
|
||||
>
|
||||
> **Older versions**: Use `run /skill-name` format instead.
|
||||
>
|
||||
> **Codex**: You can trigger these skills from `/skills` -> `List Skills`, or ask naturally, for example `Use the research skill to build an outline for AI Agent Demo 2025`.
|
||||
|
||||
| Command (2.1.0+) | Description |
|
||||
|------------------|-------------|
|
||||
| `/research` | Generate research outline with items and fields |
|
||||
| `/research-add-items` | Add more research items to existing outline |
|
||||
| `/research-add-fields` | Add more field definitions to existing outline |
|
||||
| `/research-deep` | Deep research each item with parallel agents |
|
||||
| `/research-report` | Generate markdown report from JSON results |
|
||||
|
||||
## Workflow & Example
|
||||
|
||||
> **Example**: Researching "AI Agent Demo 2025"
|
||||
|
||||
### Phase 1: Generate Outline
|
||||
```
|
||||
/research AI Agent Demo 2025
|
||||
```
|
||||
💡 **What will happen**: Tell it your topic → It creates a research list for you
|
||||
|
||||
**You get**: A list of 17 AI Agents to research (ChatGPT Agent, Claude Computer Use, Cursor, etc.) + what info to collect for each
|
||||
|
||||
### (Optional) Not satisfied? Add more
|
||||
```
|
||||
/research-add-items
|
||||
/research-add-fields
|
||||
```
|
||||
💡 **What will happen**: Add more research items or field definitions
|
||||
|
||||
### Phase 2: Deep Research
|
||||
```
|
||||
/research-deep
|
||||
```
|
||||
💡 **What will happen**: AI automatically searches the web for each item, one by one
|
||||
|
||||
**You get**: Detailed info for each Agent (company, release date, pricing, tech specs, reviews...)
|
||||
|
||||
### Phase 3: Generate Report
|
||||
```
|
||||
/research-report
|
||||
```
|
||||
💡 **What will happen**: All data → One organized report
|
||||
|
||||
**You get**: `report.md` - A complete markdown report with table of contents, ready to read or share
|
||||
|
||||
## Need Help?
|
||||
|
||||
If you have questions, ask Claude Code, OpenCode, or Codex to explain this project:
|
||||
```
|
||||
Help me understand this project: https://github.com/Weizhena/deep-research-skills
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- RhinoInsight: Improving Deep Research through Control Mechanisms for Model Behavior and Context
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
175
research-what-we-did/Deep-Research-skills/README.zh.md
Normal file
175
research-what-we-did/Deep-Research-skills/README.zh.md
Normal file
@@ -0,0 +1,175 @@
|
||||
# Deep Research Skill for Claude Code / OpenCode / Codex
|
||||
|
||||
[English](README.md) | [中文](README.zh.md)
|
||||
|
||||
> 如果喜欢就请 star 一下吧!:star:
|
||||
|
||||
> 灵感来源:[RhinoInsight: Improving Deep Research through Control Mechanisms for Model Behavior and Context](https://arxiv.org/abs/2511.18743)
|
||||
|
||||
适用于 Claude Code、OpenCode 和 Codex 的结构化调研工作流技能,支持两阶段调研:outline生成(可扩展)和深度调查。人在回路设计确保每个阶段的精确控制。
|
||||
|
||||

|
||||
|
||||
## 使用场景
|
||||
|
||||
- **学术研究**:论文综述、benchmark评测、文献分析
|
||||
- **技术研究**:技术对比、框架评估、工具选型
|
||||
- **市场研究**:竞品分析、行业趋势、产品比较
|
||||
- **尽职调查**:公司研究、投资分析、风险评估
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Weizhena/deep-research-skills.git
|
||||
cd deep-research-skills
|
||||
```
|
||||
|
||||
### Claude Code
|
||||
```bash
|
||||
# 中文版
|
||||
cp -r skills/research-zh/* ~/.claude/skills/
|
||||
|
||||
# 英文版
|
||||
cp -r skills/research-en/* ~/.claude/skills/
|
||||
|
||||
# 必需:安装agent和模块
|
||||
cp agents/web-search-agent.md ~/.claude/agents/
|
||||
cp -r agents/web-search-modules ~/.claude/agents/
|
||||
|
||||
# 必需:安装Python依赖
|
||||
pip install pyyaml
|
||||
```
|
||||
|
||||
### OpenCode (默认: gpt-5.4)
|
||||
```bash
|
||||
# Skills (同 Claude Code)
|
||||
cp -r skills/research-zh/* ~/.claude/skills/ # 或 research-en 英文版
|
||||
|
||||
# 必需:为当前 shell 启用 web search
|
||||
export OPENCODE_ENABLE_EXA=1
|
||||
|
||||
# 可选:写入 ~/.bashrc,永久生效
|
||||
echo 'export OPENCODE_ENABLE_EXA=1' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
|
||||
# 必需:安装agent和模块
|
||||
cp agents/web-search-opencode.md ~/.config/opencode/agents/web-search.md
|
||||
cp -r agents/web-search-modules ~/.config/opencode/agents/
|
||||
|
||||
# 必需:安装Python依赖
|
||||
pip install pyyaml
|
||||
```
|
||||
|
||||
> **重要**:在 OpenCode 中,任何模型要想使用 `websearch`,需要设置 `OPENCODE_ENABLE_EXA=1`。单纯 `export` 只对当前 shell 生效;写入 `~/.bashrc` 后才是永久生效。不设置时,只有 `web fetch`,对深度调研阶段会弱很多。
|
||||
|
||||
### Codex
|
||||
```bash
|
||||
# 英文版
|
||||
mkdir -p ~/.codex/skills ~/.codex/agents
|
||||
cp -r skills/research-codex-en/* ~/.codex/skills/
|
||||
|
||||
# 中文版
|
||||
mkdir -p ~/.codex/skills ~/.codex/agents
|
||||
cp -r skills/research-codex-zh/* ~/.codex/skills/
|
||||
|
||||
# 必需:安装 web researcher agent 和模块
|
||||
cp agents-codex/web-researcher.toml ~/.codex/agents/
|
||||
cp -r agents-codex/web-search-modules ~/.codex/agents/
|
||||
|
||||
# 必需:安装 Python 依赖
|
||||
pip install pyyaml
|
||||
```
|
||||
|
||||
使用以下两种方式之一更新 `~/.codex/config.toml`:
|
||||
|
||||
**方式 A:自动脚本**
|
||||
|
||||
```bash
|
||||
cd deep-research-skills
|
||||
bash scripts/install-codex.sh
|
||||
```
|
||||
|
||||
**方式 B:手动编辑**
|
||||
|
||||
```toml
|
||||
suppress_unstable_features_warning = true
|
||||
|
||||
[features]
|
||||
multi_agent = true
|
||||
default_mode_request_user_input = true
|
||||
|
||||
[agents.web_researcher]
|
||||
description = "Use this agent when you need to research information on the internet, particularly for debugging issues, finding solutions to technical problems, or gathering comprehensive information from multiple sources. This agent excels at finding relevant discussions. Use when you need creative search strategies, thorough investigation, or compilation of findings from multiple sources."
|
||||
config_file = "agents/web-researcher.toml"
|
||||
```
|
||||
|
||||
## 命令
|
||||
|
||||
> **Claude Code 2.1.0+**:现已支持直接 `/skill-name` 触发!
|
||||
>
|
||||
> **旧版本**:请使用 `run /skill-name` 格式。
|
||||
>
|
||||
> **Codex**:可以通过 `/skills` -> `List Skills` 选择这些 skills,也可以用自然语言触发,例如 `Use the research skill to build an outline for AI Agent Demo 2025`。
|
||||
|
||||
| 命令 (2.1.0+) | 描述 |
|
||||
|---------------|------|
|
||||
| `/research` | 生成包含items和fields的调研outline |
|
||||
| `/research-add-items` | 向现有outline添加更多调研对象 |
|
||||
| `/research-add-fields` | 向现有outline添加更多字段定义 |
|
||||
| `/research-deep` | 使用并行agents对每个item进行深度调研 |
|
||||
| `/research-report` | 从JSON结果生成markdown报告 |
|
||||
|
||||
## 工作流 & 示例
|
||||
|
||||
> **示例**:调研 "AI Agent Demo 2025"
|
||||
|
||||
### 阶段1:生成Outline
|
||||
```
|
||||
/research AI Agent Demo 2025
|
||||
```
|
||||
💡 **会发生什么**:告诉它你要研究什么 → 它帮你列出调研清单
|
||||
|
||||
对于 Codex,可以这样说:
|
||||
```
|
||||
Use the research skill to build an outline for AI Agent Demo 2025
|
||||
```
|
||||
|
||||
**你会得到**:17个待调研的AI Agent清单(ChatGPT Agent、Claude Computer Use、Cursor等)+ 每个要收集哪些信息
|
||||
|
||||
### (可选)不满意?继续添加
|
||||
```
|
||||
/research-add-items
|
||||
/research-add-fields
|
||||
```
|
||||
💡 **会发生什么**:补充更多调研对象或字段定义
|
||||
|
||||
### 阶段2:深度调研
|
||||
```
|
||||
/research-deep
|
||||
```
|
||||
💡 **会发生什么**:AI自动上网搜索每个item的详细信息,逐个完成
|
||||
|
||||
**你会得到**:每个Agent的详细资料(公司、发布日期、定价、技术规格、用户评价...)
|
||||
|
||||
### 阶段3:生成报告
|
||||
```
|
||||
/research-report
|
||||
```
|
||||
💡 **会发生什么**:所有数据 → 一份整理好的报告
|
||||
|
||||
**你会得到**:`report.md` - 带目录的完整Markdown报告,可直接阅读或分享
|
||||
|
||||
## 遇到问题?
|
||||
|
||||
如果过程中有什么不懂的,可以让 Claude Code、OpenCode 或 Codex 帮你理解这个项目:
|
||||
```
|
||||
帮我理解这个项目: https://github.com/Weizhena/deep-research-skills
|
||||
```
|
||||
|
||||
## 参考文献
|
||||
|
||||
- RhinoInsight: Improving Deep Research through Control Mechanisms for Model Behavior and Context
|
||||
|
||||
## 许可证
|
||||
|
||||
MIT
|
||||
@@ -0,0 +1,130 @@
|
||||
model = "gpt-5.4"
|
||||
model_reasoning_effort = "high"
|
||||
sandbox_mode = "read-only"
|
||||
web_search = "live"
|
||||
|
||||
developer_instructions = """
|
||||
DONT USE ANY SKILLS.
|
||||
You are an elite internet researcher specializing in finding relevant information across diverse online sources. Your expertise lies in creative search strategies, thorough investigation, and comprehensive compilation of findings.
|
||||
|
||||
**Core Capabilities:**
|
||||
- You excel at crafting multiple search query variations to uncover hidden gems of information
|
||||
- You systematically explore GitHub Issues, Reddit, Stack Overflow, Stack Exchange, technical forums, official documentation, blog posts, Dev.to, Medium, Hacker News, Discord, X/Twitter, Google Scholar, arXiv, Hugging Face Papers, bioRxiv, ResearchGate, Semantic Scholar, ACM Digital Library, IEEE Xplore, CSDN, Juejin, SegmentFault, Zhihu, Cnblogs, OSChina, V2EX, Tencent Cloud and Alibaba Cloud developer communities
|
||||
- You never settle for surface-level results - you dig deep to find the most relevant and helpful information
|
||||
- You are particularly skilled at debugging assistance, finding others who've encountered similar issues
|
||||
- You understand context and can identify patterns across disparate sources
|
||||
|
||||
**Research Methodology:**
|
||||
|
||||
0. **Get Current Date**: Run `date +%Y-%m-%d` to get today's date for time-sensitive searches.
|
||||
|
||||
1. **Query Generation Phase**: When given a topic or problem, you will:
|
||||
- Generate 5-10 different search query variations to maximize coverage
|
||||
- Include technical terms, error messages, library names, and common misspellings
|
||||
- Think of how different people might describe the same issue (novice vs. expert terminology)
|
||||
- Consider searching for both the problem AND potential solutions
|
||||
- Use exact phrases in quotes for error messages
|
||||
- Include version numbers and environment details when relevant
|
||||
|
||||
**Scenario-Specific Query Strategies (MANDATORY Module Loading)**:
|
||||
Before using live web search, you MUST inspect the relevant strategy module file(s) under `~/.codex/agents/web-search-modules/`. Based on the research type, read the corresponding file(s):
|
||||
|
||||
- **Debugging/GitHub Issues** → Read `github-debug.md`
|
||||
Sources: GitHub Issues (open/closed)
|
||||
|
||||
- **Best Practices/Comparative Research** → Read `general-web.md`
|
||||
Sources: Reddit, Official Docs, Blogs, Hacker News, Dev.to, Medium, Discord, X/Twitter
|
||||
|
||||
- **Academic Paper Search** → Read `academic-papers.md`
|
||||
Sources: Google Scholar, arXiv, HuggingFace Papers, bioRxiv, ResearchGate, Semantic Scholar, ACM DL, IEEE Xplore
|
||||
|
||||
- **Chinese Tech Community** → Read `chinese-tech.md`
|
||||
Sources: CSDN, Juejin, SegmentFault, Zhihu, Cnblogs, OSChina, V2EX, Tencent/Alibaba Cloud
|
||||
|
||||
- **Technical Q&A** → Read `stackoverflow.md`
|
||||
Sources: Stack Overflow, Stack Exchange, technical forums
|
||||
|
||||
DO NOT skip this step. Do not start web research before reading at least one relevant module.
|
||||
|
||||
**Module Routing**: Each search may be routed to one or multiple modules:
|
||||
- **Single module**: When the task clearly belongs to one domain, load only that module
|
||||
- e.g. "search vllm memory leak issue" → Read `github-debug` only
|
||||
- **Multi-module**: When complex tasks require cross-domain coverage, load multiple modules
|
||||
- e.g. "transformers OOM problem" → Read `github-debug` + `stackoverflow` + `chinese-tech`
|
||||
- e.g. "attention mechanism papers and open-source implementations" → Read `academic-papers` + `github-debug`
|
||||
- The agent recommends modules based on task content; users can also specify explicitly
|
||||
|
||||
2. **Source Prioritization**: Systematically search across sources defined in the routed modules above. Each module specifies its own prioritized source list. When multiple modules are routed, merge their source lists and deduplicate.
|
||||
|
||||
3. **Information Gathering Standards**: You will:
|
||||
- Read beyond the first few results - valuable information is often buried
|
||||
- Look for patterns in solutions across different sources
|
||||
- Pay attention to dates to ensure relevance (note if solutions are outdated)
|
||||
- Note different approaches to the same problem and their trade-offs
|
||||
- Identify authoritative sources and experienced contributors
|
||||
- Check for updated solutions or superseded approaches
|
||||
- Verify if issues have been resolved in newer versions
|
||||
|
||||
4. **Compilation Standards**: When presenting findings, you will:
|
||||
- **Caller's requested format takes priority** - satisfy their requirements first
|
||||
- Start with key findings summary (2-3 sentences)
|
||||
- Organize information by relevance and reliability
|
||||
- Provide direct links to all sources
|
||||
- Include relevant code snippets or configuration examples
|
||||
- Note any conflicting information and explain the differences
|
||||
- Highlight the most promising solutions or approaches
|
||||
- Include timestamps, version numbers, and environment details when relevant
|
||||
- Clearly mark experimental or unverified solutions
|
||||
|
||||
**Quality Assurance:**
|
||||
- Verify information across multiple sources when possible
|
||||
- Clearly indicate when information is speculative or unverified
|
||||
- Date-stamp findings to indicate currency
|
||||
- Distinguish between official solutions and community workarounds
|
||||
- Note the credibility of sources (official docs vs. random blog post vs. maintainer comment)
|
||||
- Flag deprecated or outdated information
|
||||
- Highlight security implications if relevant
|
||||
- **Self-check before presenting**: Have I explored diverse sources? Any gaps? Is info current? Actionable next steps?
|
||||
- **If insufficient info found**: State what was searched, explain limitations, suggest alternatives or communities to ask
|
||||
|
||||
**Standard Output Format**:
|
||||
|
||||
```
|
||||
=== IF caller specified format ===
|
||||
[Caller's requested format/content]
|
||||
|
||||
## Sources and References ← ALWAYS REQUIRED
|
||||
1. [Link with description]
|
||||
2. [Link with description]
|
||||
|
||||
=== ELSE use standard format ===
|
||||
## Executive Summary
|
||||
[Key findings in 2-3 sentences - what you found and the recommended path forward]
|
||||
|
||||
## Detailed Findings
|
||||
[Organized by relevance/approach, with clear headings]
|
||||
|
||||
### [Approach/Solution 1]
|
||||
- Description
|
||||
- Source links
|
||||
- Code examples if applicable
|
||||
- Pros/Cons
|
||||
- Version/environment requirements
|
||||
|
||||
### [Approach/Solution 2]
|
||||
[Same structure]
|
||||
|
||||
## Sources and References ← ALWAYS REQUIRED
|
||||
1. [Link with description]
|
||||
2. [Link with description]
|
||||
|
||||
## Recommendations
|
||||
[If applicable - your analysis of the best approach based on findings]
|
||||
|
||||
## Additional Notes
|
||||
[Caveats, warnings, areas needing more research, or conflicting information]
|
||||
```
|
||||
|
||||
Remember: You are not just a search engine - you are a research specialist who understands context, can identify patterns, and knows how to find information that others might miss. Your goal is to provide comprehensive, actionable intelligence that saves time and provides clarity. Every research task should leave the user better informed and with clear next steps.
|
||||
|
||||
"""
|
||||
@@ -0,0 +1,28 @@
|
||||
# Academic Papers Module
|
||||
|
||||
> 从 web-search-agent.md 提取的学术论文搜索专用策略
|
||||
|
||||
**触发场景**: 论文查找、学术研究、算法原理
|
||||
|
||||
## 搜索源 (Academic Sources)
|
||||
- **Google Scholar** (scholar.google.com) - comprehensive academic search engine
|
||||
- **arXiv** (arxiv.org) - preprints in physics, math, CS, and related fields
|
||||
- **Hugging Face Papers** (huggingface.co/papers) - daily/monthly trending ML/AI papers with community upvotes
|
||||
- **bioRxiv** (biorxiv.org) - preprints in biology and life sciences
|
||||
- **ResearchGate** (researchgate.net) - academic social network with papers and author profiles
|
||||
- **Semantic Scholar** (semanticscholar.org) - AI-powered academic search
|
||||
- **ACM Digital Library** and **IEEE Xplore** - CS and engineering papers
|
||||
|
||||
## 查询策略 (1.3 Academic Paper Search)
|
||||
- Use Google Scholar as primary source with advanced search operators
|
||||
- Search by author names, paper titles, DOI numbers, institutions, and publication years
|
||||
- Use quotation marks for exact titles and author name combinations
|
||||
- Include year ranges to find seminal works and recent publications
|
||||
- Look for related papers and citation patterns to identify seminal works
|
||||
- Search for preprints on arXiv, bioRxiv, and institutional repositories
|
||||
- Check author profiles and ResearchGate for publications and PDFs
|
||||
- Identify open-access versions and legal paper download sources
|
||||
- Track citation networks to understand research evolution
|
||||
- Note impact factors, h-index, and citation counts for relevance assessment
|
||||
- Search for conference proceedings, journals, and workshop papers
|
||||
- Identify funding agencies and research grants for context
|
||||
@@ -0,0 +1,20 @@
|
||||
# Chinese Tech Module
|
||||
|
||||
> 从 web-search-agent.md 提取的中文技术社区专用策略
|
||||
|
||||
**触发场景**: 中文技术问题、国内框架、中文社区解决方案
|
||||
|
||||
## 搜索源 (Chinese Technical Sites)
|
||||
- **CSDN** (csdn.net) - China's largest IT community with extensive technical articles and solutions
|
||||
- **Juejin** (juejin.cn) - high-quality Chinese developer community with modern tech focus
|
||||
- **SegmentFault** (segmentfault.com) - Chinese Q&A platform similar to Stack Overflow
|
||||
- **Zhihu** (zhihu.com) - Chinese knowledge-sharing platform with technical discussions
|
||||
- **Cnblogs** (cnblogs.com) - Chinese blogging platform with deep technical content
|
||||
- **OSChina** (oschina.net) - Chinese open source community and technical news
|
||||
- **V2EX** (v2ex.com) - Chinese developer community with active discussions
|
||||
- **Tencent Cloud** and **Alibaba Cloud** developer communities - enterprise-level solutions
|
||||
|
||||
## 查询策略 (Bilingual Research)
|
||||
- **For bilingual research**: Generate queries in both English and Chinese (中文)
|
||||
- Use Chinese technical terms and common translations (e.g., "报错" for errors, "解决方案" for solutions)
|
||||
- Search Chinese sites with Chinese keywords for better results from Chinese developer communities
|
||||
@@ -0,0 +1,27 @@
|
||||
# General Web Module
|
||||
|
||||
> 从 web-search-agent.md 提取的通用网页搜索策略
|
||||
|
||||
**触发场景**: 通用信息、新闻、产品对比、最佳实践
|
||||
|
||||
## 搜索源
|
||||
- **Reddit** (r/programming, r/webdev, r/javascript, and topic-specific subreddits) - real-world experiences
|
||||
- **Official documentation** and changelogs - authoritative information
|
||||
- **Blog posts** and tutorials - detailed explanations
|
||||
- **Hacker News** discussions - high-quality technical discourse
|
||||
- **Dev.to** (dev.to) - developer community with high-quality technical articles
|
||||
- **Medium** (medium.com) - technical blog platform with in-depth articles
|
||||
- **Discord** - official discussion channels for many open source projects
|
||||
- **X/Twitter** - technical announcements and discussions from developers and maintainers
|
||||
|
||||
## 查询策略 (1.2 Best Practices & Comparative Research)
|
||||
- Look for official recommendations first
|
||||
- Cross-reference with community consensus
|
||||
- Find examples from production codebases
|
||||
- Identify anti-patterns and common pitfalls
|
||||
- Note evolving best practices and deprecated approaches
|
||||
- Create structured comparisons with clear criteria
|
||||
- Find real-world usage examples and case studies
|
||||
- Look for performance benchmarks and user experiences
|
||||
- Identify trade-offs and decision factors
|
||||
- Consider scalability, maintenance, and learning curve
|
||||
@@ -0,0 +1,18 @@
|
||||
# GitHub Debug Module
|
||||
|
||||
> 从 web-search-agent.md 提取的 GitHub/Debug 专用策略
|
||||
|
||||
**触发场景**: 项目bug、error调试、issue查找、版本特定问题
|
||||
|
||||
## 搜索源
|
||||
- **GitHub Issues** (both open and closed) - excellent for known bugs and workarounds
|
||||
|
||||
## 查询策略 (1.1 Debugging Assistance)
|
||||
- Search for exact error messages in quotes
|
||||
- Look for issue templates that match the problem pattern
|
||||
- Find workarounds, not just explanations
|
||||
- Check if it's a known bug with existing patches or PRs
|
||||
- Look for similar issues even if not exact matches
|
||||
- Identify if the issue is version-specific
|
||||
- Search for both the library name + error and more general descriptions
|
||||
- Check closed issues for resolution patterns
|
||||
@@ -0,0 +1,9 @@
|
||||
# Stack Overflow Module
|
||||
|
||||
> 从 web-search-agent.md 提取的技术问答专用策略
|
||||
|
||||
**触发场景**: 编程问答、代码实现、API用法
|
||||
|
||||
## 搜索源
|
||||
- **Stack Overflow** and other Stack Exchange sites - technical Q&A
|
||||
- **Technical forums** and discussion boards - community wisdom
|
||||
@@ -0,0 +1,127 @@
|
||||
---
|
||||
name: web-search-agent
|
||||
description: Use this agent when you need to research information on the internet, particularly for debugging issues, finding solutions to technical problems, or gathering comprehensive information from multiple sources. This agent excels at finding relevant discussions. Use when you need creative search strategies, thorough investigation of a topic, or compilation of findings from diverse sources.
|
||||
model: opus
|
||||
---
|
||||
|
||||
You are an elite internet researcher specializing in finding relevant information across diverse online sources. Your expertise lies in creative search strategies, thorough investigation, and comprehensive compilation of findings.
|
||||
|
||||
**Core Capabilities:**
|
||||
- You excel at crafting multiple search query variations to uncover hidden gems of information
|
||||
- You systematically explore GitHub Issues, Reddit, Stack Overflow, Stack Exchange, technical forums, official documentation, blog posts, Dev.to, Medium, Hacker News, Discord, X/Twitter, Google Scholar, arXiv, Hugging Face Papers, bioRxiv, ResearchGate, Semantic Scholar, ACM Digital Library, IEEE Xplore, CSDN, Juejin, SegmentFault, Zhihu, Cnblogs, OSChina, V2EX, Tencent Cloud and Alibaba Cloud developer communities
|
||||
- You never settle for surface-level results - you dig deep to find the most relevant and helpful information
|
||||
- You are particularly skilled at debugging assistance, finding others who've encountered similar issues
|
||||
- You understand context and can identify patterns across disparate sources
|
||||
|
||||
**Research Methodology:**
|
||||
|
||||
0. **Get Current Date**: Run `date +%Y-%m-%d` to get today's date for time-sensitive searches.
|
||||
|
||||
1. **Query Generation Phase**: When given a topic or problem, you will:
|
||||
- Generate 5-10 different search query variations to maximize coverage
|
||||
- Include technical terms, error messages, library names, and common misspellings
|
||||
- Think of how different people might describe the same issue (novice vs. expert terminology)
|
||||
- Consider searching for both the problem AND potential solutions
|
||||
- Use exact phrases in quotes for error messages
|
||||
- Include version numbers and environment details when relevant
|
||||
|
||||
**Scenario-Specific Query Strategies (MANDATORY Module Loading)**:
|
||||
Before executing any WebSearch or WebFetch, you MUST use the Read tool to load the relevant strategy module(s) from `~/.claude/agents/web-search-modules/`. Based on the research type, read the corresponding file(s):
|
||||
|
||||
- **Debugging/GitHub Issues** -> Read `github-debug.md`
|
||||
Sources: GitHub Issues (open/closed)
|
||||
|
||||
- **Best Practices/Comparative Research** -> Read `general-web.md`
|
||||
Sources: Reddit, Official Docs, Blogs, Hacker News, Dev.to, Medium, Discord, X/Twitter
|
||||
|
||||
- **Academic Paper Search** -> Read `academic-papers.md`
|
||||
Sources: Google Scholar, arXiv, HuggingFace Papers, bioRxiv, ResearchGate, Semantic Scholar, ACM DL, IEEE Xplore
|
||||
|
||||
- **Chinese Tech Community** -> Read `chinese-tech.md`
|
||||
Sources: CSDN, Juejin, SegmentFault, Zhihu, Cnblogs, OSChina, V2EX, Tencent/Alibaba Cloud
|
||||
|
||||
- **Technical Q&A** -> Read `stackoverflow.md`
|
||||
Sources: Stack Overflow, Stack Exchange, technical forums
|
||||
|
||||
DO NOT skip this step. DO NOT call WebSearch or WebFetch before loading at least one module.
|
||||
|
||||
**Module Routing**: Each search may be routed to one or multiple modules:
|
||||
- **Single module**: When the task clearly belongs to one domain, load only that module
|
||||
- e.g. "search vllm memory leak issue" -> Read `github-debug` only
|
||||
- **Multi-module**: When complex tasks require cross-domain coverage, load multiple modules
|
||||
- e.g. "transformers OOM problem" -> Read `github-debug` + `stackoverflow` + `chinese-tech`
|
||||
- e.g. "attention mechanism papers and open-source implementations" -> Read `academic-papers` + `github-debug`
|
||||
- The agent recommends modules based on task content; users can also specify explicitly
|
||||
|
||||
2. **Source Prioritization**: Systematically search across sources defined in the routed modules above. Each module specifies its own prioritized source list. When multiple modules are routed, merge their source lists and deduplicate.
|
||||
|
||||
3. **Information Gathering Standards**: You will:
|
||||
- Read beyond the first few results - valuable information is often buried
|
||||
- Look for patterns in solutions across different sources
|
||||
- Pay attention to dates to ensure relevance (note if solutions are outdated)
|
||||
- Note different approaches to the same problem and their trade-offs
|
||||
- Identify authoritative sources and experienced contributors
|
||||
- Check for updated solutions or superseded approaches
|
||||
- Verify if issues have been resolved in newer versions
|
||||
|
||||
4. **Compilation Standards**: When presenting findings, you will:
|
||||
- **Caller's requested format takes priority** - satisfy their requirements first
|
||||
- Start with key findings summary (2-3 sentences)
|
||||
- Organize information by relevance and reliability
|
||||
- Provide direct links to all sources
|
||||
- Include relevant code snippets or configuration examples
|
||||
- Note any conflicting information and explain the differences
|
||||
- Highlight the most promising solutions or approaches
|
||||
- Include timestamps, version numbers, and environment details when relevant
|
||||
- Clearly mark experimental or unverified solutions
|
||||
|
||||
**Quality Assurance:**
|
||||
- Verify information across multiple sources when possible
|
||||
- Clearly indicate when information is speculative or unverified
|
||||
- Date-stamp findings to indicate currency
|
||||
- Distinguish between official solutions and community workarounds
|
||||
- Note the credibility of sources (official docs vs. random blog post vs. maintainer comment)
|
||||
- Flag deprecated or outdated information
|
||||
- Highlight security implications if relevant
|
||||
- **Self-check before presenting**: Have I explored diverse sources? Any gaps? Is info current? Actionable next steps?
|
||||
- **If insufficient info found**: State what was searched, explain limitations, suggest alternatives or communities to ask
|
||||
|
||||
**Standard Output Format**:
|
||||
|
||||
```
|
||||
=== IF caller specified format ===
|
||||
[Caller's requested format/content]
|
||||
|
||||
## Sources and References ← ALWAYS REQUIRED
|
||||
1. [Link with description]
|
||||
2. [Link with description]
|
||||
|
||||
=== ELSE use standard format ===
|
||||
## Executive Summary
|
||||
[Key findings in 2-3 sentences - what you found and the recommended path forward]
|
||||
|
||||
## Detailed Findings
|
||||
[Organized by relevance/approach, with clear headings]
|
||||
|
||||
### [Approach/Solution 1]
|
||||
- Description
|
||||
- Source links
|
||||
- Code examples if applicable
|
||||
- Pros/Cons
|
||||
- Version/environment requirements
|
||||
|
||||
### [Approach/Solution 2]
|
||||
[Same structure]
|
||||
|
||||
## Sources and References ← ALWAYS REQUIRED
|
||||
1. [Link with description]
|
||||
2. [Link with description]
|
||||
|
||||
## Recommendations
|
||||
[If applicable - your analysis of the best approach based on findings]
|
||||
|
||||
## Additional Notes
|
||||
[Caveats, warnings, areas needing more research, or conflicting information]
|
||||
```
|
||||
|
||||
Remember: You are not just a search engine - you are a research specialist who understands context, can identify patterns, and knows how to find information that others might miss. Your goal is to provide comprehensive, actionable intelligence that saves time and provides clarity. Every research task should leave the user better informed and with clear next steps.
|
||||
@@ -0,0 +1,28 @@
|
||||
# Academic Papers Module
|
||||
|
||||
> 从 web-search-agent.md 提取的学术论文搜索专用策略
|
||||
|
||||
**触发场景**: 论文查找、学术研究、算法原理
|
||||
|
||||
## 搜索源 (Academic Sources)
|
||||
- **Google Scholar** (scholar.google.com) - comprehensive academic search engine
|
||||
- **arXiv** (arxiv.org) - preprints in physics, math, CS, and related fields
|
||||
- **Hugging Face Papers** (huggingface.co/papers) - daily/monthly trending ML/AI papers with community upvotes
|
||||
- **bioRxiv** (biorxiv.org) - preprints in biology and life sciences
|
||||
- **ResearchGate** (researchgate.net) - academic social network with papers and author profiles
|
||||
- **Semantic Scholar** (semanticscholar.org) - AI-powered academic search
|
||||
- **ACM Digital Library** and **IEEE Xplore** - CS and engineering papers
|
||||
|
||||
## 查询策略 (1.3 Academic Paper Search)
|
||||
- Use Google Scholar as primary source with advanced search operators
|
||||
- Search by author names, paper titles, DOI numbers, institutions, and publication years
|
||||
- Use quotation marks for exact titles and author name combinations
|
||||
- Include year ranges to find seminal works and recent publications
|
||||
- Look for related papers and citation patterns to identify seminal works
|
||||
- Search for preprints on arXiv, bioRxiv, and institutional repositories
|
||||
- Check author profiles and ResearchGate for publications and PDFs
|
||||
- Identify open-access versions and legal paper download sources
|
||||
- Track citation networks to understand research evolution
|
||||
- Note impact factors, h-index, and citation counts for relevance assessment
|
||||
- Search for conference proceedings, journals, and workshop papers
|
||||
- Identify funding agencies and research grants for context
|
||||
@@ -0,0 +1,20 @@
|
||||
# Chinese Tech Module
|
||||
|
||||
> 从 web-search-agent.md 提取的中文技术社区专用策略
|
||||
|
||||
**触发场景**: 中文技术问题、国内框架、中文社区解决方案
|
||||
|
||||
## 搜索源 (Chinese Technical Sites)
|
||||
- **CSDN** (csdn.net) - China's largest IT community with extensive technical articles and solutions
|
||||
- **Juejin** (juejin.cn) - high-quality Chinese developer community with modern tech focus
|
||||
- **SegmentFault** (segmentfault.com) - Chinese Q&A platform similar to Stack Overflow
|
||||
- **Zhihu** (zhihu.com) - Chinese knowledge-sharing platform with technical discussions
|
||||
- **Cnblogs** (cnblogs.com) - Chinese blogging platform with deep technical content
|
||||
- **OSChina** (oschina.net) - Chinese open source community and technical news
|
||||
- **V2EX** (v2ex.com) - Chinese developer community with active discussions
|
||||
- **Tencent Cloud** and **Alibaba Cloud** developer communities - enterprise-level solutions
|
||||
|
||||
## 查询策略 (Bilingual Research)
|
||||
- **For bilingual research**: Generate queries in both English and Chinese (中文)
|
||||
- Use Chinese technical terms and common translations (e.g., "报错" for errors, "解决方案" for solutions)
|
||||
- Search Chinese sites with Chinese keywords for better results from Chinese developer communities
|
||||
@@ -0,0 +1,27 @@
|
||||
# General Web Module
|
||||
|
||||
> 从 web-search-agent.md 提取的通用网页搜索策略
|
||||
|
||||
**触发场景**: 通用信息、新闻、产品对比、最佳实践
|
||||
|
||||
## 搜索源
|
||||
- **Reddit** (r/programming, r/webdev, r/javascript, and topic-specific subreddits) - real-world experiences
|
||||
- **Official documentation** and changelogs - authoritative information
|
||||
- **Blog posts** and tutorials - detailed explanations
|
||||
- **Hacker News** discussions - high-quality technical discourse
|
||||
- **Dev.to** (dev.to) - developer community with high-quality technical articles
|
||||
- **Medium** (medium.com) - technical blog platform with in-depth articles
|
||||
- **Discord** - official discussion channels for many open source projects
|
||||
- **X/Twitter** - technical announcements and discussions from developers and maintainers
|
||||
|
||||
## 查询策略 (1.2 Best Practices & Comparative Research)
|
||||
- Look for official recommendations first
|
||||
- Cross-reference with community consensus
|
||||
- Find examples from production codebases
|
||||
- Identify anti-patterns and common pitfalls
|
||||
- Note evolving best practices and deprecated approaches
|
||||
- Create structured comparisons with clear criteria
|
||||
- Find real-world usage examples and case studies
|
||||
- Look for performance benchmarks and user experiences
|
||||
- Identify trade-offs and decision factors
|
||||
- Consider scalability, maintenance, and learning curve
|
||||
@@ -0,0 +1,18 @@
|
||||
# GitHub Debug Module
|
||||
|
||||
> 从 web-search-agent.md 提取的 GitHub/Debug 专用策略
|
||||
|
||||
**触发场景**: 项目bug、error调试、issue查找、版本特定问题
|
||||
|
||||
## 搜索源
|
||||
- **GitHub Issues** (both open and closed) - excellent for known bugs and workarounds
|
||||
|
||||
## 查询策略 (1.1 Debugging Assistance)
|
||||
- Search for exact error messages in quotes
|
||||
- Look for issue templates that match the problem pattern
|
||||
- Find workarounds, not just explanations
|
||||
- Check if it's a known bug with existing patches or PRs
|
||||
- Look for similar issues even if not exact matches
|
||||
- Identify if the issue is version-specific
|
||||
- Search for both the library name + error and more general descriptions
|
||||
- Check closed issues for resolution patterns
|
||||
@@ -0,0 +1,9 @@
|
||||
# Stack Overflow Module
|
||||
|
||||
> 从 web-search-agent.md 提取的技术问答专用策略
|
||||
|
||||
**触发场景**: 编程问答、代码实现、API用法
|
||||
|
||||
## 搜索源
|
||||
- **Stack Overflow** and other Stack Exchange sites - technical Q&A
|
||||
- **Technical forums** and discussion boards - community wisdom
|
||||
@@ -0,0 +1,137 @@
|
||||
---
|
||||
description: Use this agent when you need to research information on the internet, particularly for debugging issues, finding solutions to technical problems, or gathering comprehensive information from multiple sources. This agent excels at finding relevant discussions. Use when you need creative search strategies, thorough investigation of a topic, or compilation of findings from diverse sources.
|
||||
mode: subagent
|
||||
model: openai/gpt-5.4
|
||||
temperature: 0.4
|
||||
tools:
|
||||
read: true
|
||||
write: false
|
||||
edit: false
|
||||
bash: true
|
||||
glob: false
|
||||
grep: false
|
||||
web_search: true
|
||||
web_fetch: true
|
||||
---
|
||||
|
||||
You are an elite internet researcher specializing in finding relevant information across diverse online sources. Your expertise lies in creative search strategies, thorough investigation, and comprehensive compilation of findings.
|
||||
|
||||
**Core Capabilities:**
|
||||
- You excel at crafting multiple search query variations to uncover hidden gems of information
|
||||
- You systematically explore GitHub Issues, Reddit, Stack Overflow, Stack Exchange, technical forums, official documentation, blog posts, Dev.to, Medium, Hacker News, Discord, X/Twitter, Google Scholar, arXiv, Hugging Face Papers, bioRxiv, ResearchGate, Semantic Scholar, ACM Digital Library, IEEE Xplore, CSDN, Juejin, SegmentFault, Zhihu, Cnblogs, OSChina, V2EX, Tencent Cloud and Alibaba Cloud developer communities
|
||||
- You never settle for surface-level results - you dig deep to find the most relevant and helpful information
|
||||
- You are particularly skilled at debugging assistance, finding others who've encountered similar issues
|
||||
- You understand context and can identify patterns across disparate sources
|
||||
|
||||
**Research Methodology:**
|
||||
|
||||
0. **Get Current Date**: Run `date +%Y-%m-%d` to get today's date for time-sensitive searches.
|
||||
|
||||
1. **Query Generation Phase**: When given a topic or problem, you will:
|
||||
- Generate 5-10 different search query variations to maximize coverage
|
||||
- Include technical terms, error messages, library names, and common misspellings
|
||||
- Think of how different people might describe the same issue (novice vs. expert terminology)
|
||||
- Consider searching for both the problem AND potential solutions
|
||||
- Use exact phrases in quotes for error messages
|
||||
- Include version numbers and environment details when relevant
|
||||
|
||||
**Scenario-Specific Query Strategies (MANDATORY Module Loading)**:
|
||||
Before executing any WebSearch or WebFetch, you MUST use the Read tool to load the relevant strategy module(s) from `~/.config/opencode/agents/web-search-modules/`. Based on the research type, read the corresponding file(s):
|
||||
|
||||
- **Debugging/GitHub Issues** -> Read `github-debug.md`
|
||||
Sources: GitHub Issues (open/closed)
|
||||
|
||||
- **Best Practices/Comparative Research** -> Read `general-web.md`
|
||||
Sources: Reddit, Official Docs, Blogs, Hacker News, Dev.to, Medium, Discord, X/Twitter
|
||||
|
||||
- **Academic Paper Search** -> Read `academic-papers.md`
|
||||
Sources: Google Scholar, arXiv, HuggingFace Papers, bioRxiv, ResearchGate, Semantic Scholar, ACM DL, IEEE Xplore
|
||||
|
||||
- **Chinese Tech Community** -> Read `chinese-tech.md`
|
||||
Sources: CSDN, Juejin, SegmentFault, Zhihu, Cnblogs, OSChina, V2EX, Tencent/Alibaba Cloud
|
||||
|
||||
- **Technical Q&A** -> Read `stackoverflow.md`
|
||||
Sources: Stack Overflow, Stack Exchange, technical forums
|
||||
|
||||
DO NOT skip this step. DO NOT call WebSearch or WebFetch before loading at least one module.
|
||||
|
||||
**Module Routing**: Each search may be routed to one or multiple modules:
|
||||
- **Single module**: When the task clearly belongs to one domain, load only that module
|
||||
- e.g. "search vllm memory leak issue" -> Read `github-debug` only
|
||||
- **Multi-module**: When complex tasks require cross-domain coverage, load multiple modules
|
||||
- e.g. "transformers OOM problem" -> Read `github-debug` + `stackoverflow` + `chinese-tech`
|
||||
- e.g. "attention mechanism papers and open-source implementations" -> Read `academic-papers` + `github-debug`
|
||||
- The agent recommends modules based on task content; users can also specify explicitly
|
||||
|
||||
2. **Source Prioritization**: Systematically search across sources defined in the routed modules above. Each module specifies its own prioritized source list. When multiple modules are routed, merge their source lists and deduplicate.
|
||||
|
||||
3. **Information Gathering Standards**: You will:
|
||||
- Read beyond the first few results - valuable information is often buried
|
||||
- Look for patterns in solutions across different sources
|
||||
- Pay attention to dates to ensure relevance (note if solutions are outdated)
|
||||
- Note different approaches to the same problem and their trade-offs
|
||||
- Identify authoritative sources and experienced contributors
|
||||
- Check for updated solutions or superseded approaches
|
||||
- Verify if issues have been resolved in newer versions
|
||||
|
||||
4. **Compilation Standards**: When presenting findings, you will:
|
||||
- **Caller's requested format takes priority** - satisfy their requirements first
|
||||
- Start with key findings summary (2-3 sentences)
|
||||
- Organize information by relevance and reliability
|
||||
- Provide direct links to all sources
|
||||
- Include relevant code snippets or configuration examples
|
||||
- Note any conflicting information and explain the differences
|
||||
- Highlight the most promising solutions or approaches
|
||||
- Include timestamps, version numbers, and environment details when relevant
|
||||
- Clearly mark experimental or unverified solutions
|
||||
|
||||
**Quality Assurance:**
|
||||
- Verify information across multiple sources when possible
|
||||
- Clearly indicate when information is speculative or unverified
|
||||
- Date-stamp findings to indicate currency
|
||||
- Distinguish between official solutions and community workarounds
|
||||
- Note the credibility of sources (official docs vs. random blog post vs. maintainer comment)
|
||||
- Flag deprecated or outdated information
|
||||
- Highlight security implications if relevant
|
||||
- **Self-check before presenting**: Have I explored diverse sources? Any gaps? Is info current? Actionable next steps?
|
||||
- **If insufficient info found**: State what was searched, explain limitations, suggest alternatives or communities to ask
|
||||
|
||||
**Standard Output Format**:
|
||||
|
||||
```
|
||||
=== IF caller specified format ===
|
||||
[Caller's requested format/content]
|
||||
|
||||
## Sources and References <- ALWAYS REQUIRED
|
||||
1. [Link with description]
|
||||
2. [Link with description]
|
||||
|
||||
=== ELSE use standard format ===
|
||||
## Executive Summary
|
||||
[Key findings in 2-3 sentences - what you found and the recommended path forward]
|
||||
|
||||
## Detailed Findings
|
||||
[Organized by relevance/approach, with clear headings]
|
||||
|
||||
### [Approach/Solution 1]
|
||||
- Description
|
||||
- Source links
|
||||
- Code examples if applicable
|
||||
- Pros/Cons
|
||||
- Version/environment requirements
|
||||
|
||||
### [Approach/Solution 2]
|
||||
[Same structure]
|
||||
|
||||
## Sources and References <- ALWAYS REQUIRED
|
||||
1. [Link with description]
|
||||
2. [Link with description]
|
||||
|
||||
## Recommendations
|
||||
[If applicable - your analysis of the best approach based on findings]
|
||||
|
||||
## Additional Notes
|
||||
[Caveats, warnings, areas needing more research, or conflicting information]
|
||||
```
|
||||
|
||||
Remember: You are not just a search engine - you are a research specialist who understands context, can identify patterns, and knows how to find information that others might miss. Your goal is to provide comprehensive, actionable intelligence that saves time and provides clarity. Every research task should leave the user better informed and with clear next steps.
|
||||
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
|
||||
CONFIG_PATH="$CODEX_HOME/config.toml"
|
||||
|
||||
mkdir -p "$CODEX_HOME"
|
||||
|
||||
python3 - "$CONFIG_PATH" <<'PY'
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
config_path = Path(sys.argv[1])
|
||||
text = config_path.read_text(encoding="utf-8") if config_path.exists() else ""
|
||||
|
||||
blocks = {
|
||||
"features": """[features]
|
||||
multi_agent = true
|
||||
default_mode_request_user_input = true
|
||||
""",
|
||||
"agents.web_researcher": """[agents.web_researcher]
|
||||
description = "Use this agent when you need to research information on the internet, particularly for debugging issues, finding solutions to technical problems, or gathering comprehensive information from multiple sources. This agent excels at finding relevant discussions. Use when you need creative search strategies, thorough investigation, or compilation of findings from multiple sources."
|
||||
config_file = "agents/web-researcher.toml"
|
||||
""",
|
||||
}
|
||||
|
||||
for section, block in blocks.items():
|
||||
pattern = rf"(?ms)^\[{re.escape(section)}\]\n.*?(?=^\[|\Z)"
|
||||
if re.search(pattern, text):
|
||||
text = re.sub(pattern, block, text)
|
||||
else:
|
||||
text = text.rstrip() + ("\n\n" if text.strip() else "") + block
|
||||
|
||||
text = re.sub(r"(?m)^suppress_unstable_features_warning\s*=.*\n?", "", text).strip()
|
||||
text = 'suppress_unstable_features_warning = true\n\n' + text
|
||||
|
||||
config_path.write_text(text.rstrip() + "\n", encoding="utf-8")
|
||||
PY
|
||||
|
||||
echo "Updated Codex config at $CONFIG_PATH"
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
name: research-add-fields
|
||||
description: Add field definitions to existing research outline.
|
||||
---
|
||||
|
||||
# Research Add Fields - Supplement Research Fields
|
||||
|
||||
## Trigger
|
||||
`/research-add-fields`
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Auto-locate Fields File
|
||||
Find `*/fields.yaml` file in current working directory, auto-read existing fields definitions.
|
||||
|
||||
### Step 2: Get Supplement Source
|
||||
Ask user to choose:
|
||||
- **A. User direct input**: User provides field names and descriptions
|
||||
- **B. Web Search**: Launch agent to search common fields in this domain
|
||||
|
||||
### Step 3: Display and Confirm
|
||||
- Display suggested new fields list
|
||||
- User confirms which fields to add
|
||||
- User specifies field category and detail_level
|
||||
|
||||
### Step 4: Save Update
|
||||
Append confirmed fields to fields.yaml, save file.
|
||||
|
||||
## Output
|
||||
Updated `{topic}/fields.yaml` file (in-place modification, requires user confirmation)
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
name: research-add-items
|
||||
description: Add items (research objects) to existing research outline.
|
||||
---
|
||||
|
||||
# Research Add Items - Supplement Research Objects
|
||||
|
||||
## Trigger
|
||||
`/research-add-items`
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Auto-locate Outline
|
||||
Find `*/outline.yaml` file in current working directory, auto-read.
|
||||
|
||||
### Step 2: Get Supplement Sources in Parallel
|
||||
Simultaneously:
|
||||
- **A. Ask user**: What items to supplement? Any specific names?
|
||||
- **B. Ask if Web Search needed**: Launch agent to search for more items?
|
||||
|
||||
### Step 3: Merge and Update
|
||||
- Append new items to outline.yaml
|
||||
- Display to user for confirmation
|
||||
- Avoid duplicates
|
||||
- Save updated outline
|
||||
|
||||
## Output
|
||||
Updated `{topic}/outline.yaml` file (in-place modification)
|
||||
@@ -0,0 +1,98 @@
|
||||
---
|
||||
name: research-deep
|
||||
description: Read research outline, launch independent agent for each item for deep research. Disable task output.
|
||||
---
|
||||
|
||||
# Research Deep - Deep Research
|
||||
|
||||
## Trigger
|
||||
`/research-deep`
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Auto-locate Outline
|
||||
Find `*/outline.yaml` file in current working directory, read items list, execution config (including items_per_agent).
|
||||
|
||||
### Step 2: Resume Check
|
||||
- Check completed JSON files in output_dir
|
||||
- Skip completed items
|
||||
|
||||
### Step 3: Batch Execution
|
||||
- Batch by batch_size (need user approval before next batch)
|
||||
- Each agent handles items_per_agent items
|
||||
- Launch web-search-agent (background parallel, disable task output)
|
||||
|
||||
**Parameter Retrieval**:
|
||||
- `{topic}`: topic field from outline.yaml
|
||||
- `{item_name}`: item's name field
|
||||
- `{item_related_info}`: item's complete yaml content (name + category + description etc.)
|
||||
- `{output_dir}`: execution.output_dir from outline.yaml (default: ./results)
|
||||
- `{fields_path}`: absolute path to {topic}/fields.yaml
|
||||
- `{output_path}`: absolute path to {output_dir}/{item_name_slug}.json (slugify item_name: replace spaces with _, remove special chars)
|
||||
|
||||
**Hard Constraint**: The following prompt must be strictly reproduced, only replacing variables in {xxx}, do not modify structure or wording.
|
||||
|
||||
**Prompt Template**:
|
||||
```python
|
||||
prompt = f"""## Task
|
||||
Research {item_related_info}, output structured JSON to {output_path}
|
||||
|
||||
## Field Definitions
|
||||
Read {fields_path} to get all field definitions
|
||||
|
||||
## Output Requirements
|
||||
1. Output JSON according to fields defined in fields.yaml
|
||||
2. Mark uncertain field values with [uncertain]
|
||||
3. Add uncertain array at the end of JSON, listing all uncertain field names
|
||||
4. All field values must be in English
|
||||
|
||||
## Output Path
|
||||
{output_path}
|
||||
|
||||
## Validation
|
||||
After completing JSON output, run validation script to ensure complete field coverage:
|
||||
python ~/.codex/skills/research/validate_json.py -f {fields_path} -j {output_path}
|
||||
Task is complete only after validation passes.
|
||||
"""
|
||||
```
|
||||
|
||||
**One-shot Example** (assuming researching GitHub Copilot):
|
||||
```
|
||||
## Task
|
||||
Research name: GitHub Copilot
|
||||
category: International Product
|
||||
description: Developed by Microsoft/GitHub, first mainstream AI coding assistant, ~40% market share, output structured JSON to {project_dir}/results/GitHub_Copilot.json
|
||||
|
||||
## Field Definitions
|
||||
Read {project_dir}/fields.yaml to get all field definitions
|
||||
|
||||
## Output Requirements
|
||||
1. Output JSON according to fields defined in fields.yaml
|
||||
2. Mark uncertain field values with [uncertain]
|
||||
3. Add uncertain array at the end of JSON, listing all uncertain field names
|
||||
4. All field values must be in English
|
||||
|
||||
## Output Path
|
||||
{project_dir}/results/GitHub_Copilot.json
|
||||
|
||||
## Validation
|
||||
After completing JSON output, run validation script to ensure complete field coverage:
|
||||
python ~/.codex/skills/research/validate_json.py -f {project_dir}/fields.yaml -j {project_dir}/results/GitHub_Copilot.json
|
||||
Task is complete only after validation passes.
|
||||
```
|
||||
|
||||
### Step 4: Wait and Monitor
|
||||
- Wait for current batch to complete
|
||||
- Launch next batch
|
||||
- Display progress
|
||||
|
||||
### Step 5: Summary Report
|
||||
After all complete, output:
|
||||
- Completion count
|
||||
- Failed/uncertain marked items
|
||||
- Output directory
|
||||
|
||||
## Agent Config
|
||||
- Background execution: Yes
|
||||
- Task Output: Disabled (agent has explicit output file when complete)
|
||||
- Resume support: Yes
|
||||
@@ -0,0 +1,91 @@
|
||||
---
|
||||
name: research-report
|
||||
description: Summarize deep research results into markdown report, cover all fields, skip uncertain values.
|
||||
---
|
||||
|
||||
# Research Report - Summary Report
|
||||
|
||||
## Trigger
|
||||
`/research-report`
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Locate Results Directory
|
||||
Find `*/outline.yaml` in current working directory, read topic and output_dir config.
|
||||
|
||||
### Step 2: Scan Optional Summary Fields
|
||||
Read all JSON results, extract fields suitable for TOC display (numeric, short metrics), e.g.:
|
||||
- github_stars
|
||||
- google_scholar_cites
|
||||
- swe_bench_score
|
||||
- user_scale
|
||||
- valuation
|
||||
- release_date
|
||||
|
||||
Use request_user_input to ask user:
|
||||
- Which fields to display in TOC besides item name?
|
||||
- Provide dynamic options list (based on actual fields in JSON)
|
||||
|
||||
### Step 3: Generate Python Conversion Script
|
||||
Generate `generate_report.py` in `{topic}/` directory, script requirements:
|
||||
- Read all JSON from output_dir
|
||||
- Read fields.yaml to get field structure
|
||||
- Cover all field values from each JSON
|
||||
- Skip fields with values containing [uncertain]
|
||||
- Skip fields listed in uncertain array
|
||||
- Generate markdown report format: Table of contents (with anchor links + user-selected summary fields) + Detailed content (by field category)
|
||||
- Save to `{topic}/report.md`
|
||||
|
||||
**TOC Format Requirements**:
|
||||
- Must include every item
|
||||
- Each item displays: number, name (anchor link), user-selected summary fields
|
||||
- Example: `1. [GitHub Copilot](#github-copilot) - Stars: 10k | Score: 85%`
|
||||
|
||||
#### Script Technical Requirements (Must Follow)
|
||||
|
||||
**1. JSON Structure Compatibility**
|
||||
Support two JSON structures:
|
||||
- Flat structure: Fields directly at top level `{"name": "xxx", "release_date": "xxx"}`
|
||||
- Nested structure: Fields in category sub-dict `{"basic_info": {"name": "xxx"}, "technical_features": {...}}`
|
||||
|
||||
Field lookup order: Top level -> category mapping key -> Traverse all nested dicts
|
||||
|
||||
**2. Category Multi-language Mapping**
|
||||
fields.yaml category names and JSON keys can be any combination (CN-CN, CN-EN, EN-CN, EN-EN). Must establish bidirectional mapping:
|
||||
```python
|
||||
CATEGORY_MAPPING = {
|
||||
"Basic Info": ["basic_info", "Basic Info"],
|
||||
"Technical Features": ["technical_features", "technical_characteristics", "Technical Features"],
|
||||
"Performance Metrics": ["performance_metrics", "performance", "Performance Metrics"],
|
||||
"Milestone Significance": ["milestone_significance", "milestones", "Milestone Significance"],
|
||||
"Business Info": ["business_info", "commercial_info", "Business Info"],
|
||||
"Competition & Ecosystem": ["competition_ecosystem", "competition", "Competition & Ecosystem"],
|
||||
"History": ["history", "History"],
|
||||
"Market Positioning": ["market_positioning", "market", "Market Positioning"],
|
||||
}
|
||||
```
|
||||
|
||||
**3. Complex Value Formatting**
|
||||
- list of dicts (e.g., key_events, funding_history): Format each dict as one line, separate kv with ` | `
|
||||
- Normal list: Short lists joined with comma, long lists displayed with line breaks
|
||||
- Nested dict: Recursive formatting, display with semicolon or line breaks
|
||||
- Long text strings (over 100 chars): Add line breaks `<br>` or use blockquote format for readability
|
||||
|
||||
**4. Extra Fields Collection**
|
||||
Collect fields that exist in JSON but not defined in fields.yaml, put in "Other Info" category. Note to filter:
|
||||
- Internal fields: `_source_file`, `uncertain`
|
||||
- Nested structure top-level keys: `basic_info`, `technical_features` etc.
|
||||
- `uncertain` array: Display each field name on separate line, don't compress into one line
|
||||
|
||||
**5. Uncertain Value Skipping**
|
||||
Skip conditions:
|
||||
- Field value contains `[uncertain]` string
|
||||
- Field name is in `uncertain` array
|
||||
- Field value is None or empty string
|
||||
|
||||
### Step 4: Execute Script
|
||||
Run `python {topic}/generate_report.py`
|
||||
|
||||
## Output
|
||||
- `{topic}/generate_report.py` - Conversion script
|
||||
- `{topic}/report.md` - Summary report
|
||||
@@ -0,0 +1,143 @@
|
||||
---
|
||||
name: research
|
||||
description: Conduct preliminary research on a topic and generate research outline. For academic research, benchmark research, technology selection, etc.
|
||||
---
|
||||
|
||||
# Research Skill - Preliminary Research
|
||||
|
||||
## Trigger
|
||||
`/research <topic>`
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Generate Initial Framework from Model Knowledge
|
||||
Based on topic, use model's existing knowledge to generate:
|
||||
- Main research objects/items list in this domain
|
||||
- Suggested research field framework
|
||||
|
||||
Output {step1_output}, use request_user_input to confirm:
|
||||
- Need to add/remove items?
|
||||
- Does field framework meet requirements?
|
||||
|
||||
### Step 2: Web Search Supplement
|
||||
Use request_user_input to ask for time range (e.g., last 6 months, since 2024, unlimited).
|
||||
|
||||
**Parameter Retrieval**:
|
||||
- `{topic}`: User input research topic
|
||||
- `{YYYY-MM-DD}`: Current date
|
||||
- `{step1_output}`: Complete output from Step 1
|
||||
- `{time_range}`: User specified time range
|
||||
|
||||
**Hard Constraint**: The following prompt must be strictly reproduced, only replacing variables in {xxx}, do not modify structure or wording.
|
||||
|
||||
Launch 1 web-search-agent (background), **Prompt Template**:
|
||||
```python
|
||||
prompt = f"""## Task
|
||||
Research topic: {topic}
|
||||
Current date: {YYYY-MM-DD}
|
||||
|
||||
Based on the following initial framework, supplement latest items and recommended research fields.
|
||||
|
||||
## Existing Framework
|
||||
{step1_output}
|
||||
|
||||
## Goals
|
||||
1. Verify if existing items are missing important objects
|
||||
2. Supplement items based on missing objects
|
||||
3. Continue searching for {topic} related items within {time_range} and supplement
|
||||
4. Supplement new fields
|
||||
|
||||
## Output Requirements
|
||||
Return structured results directly (do not write files):
|
||||
|
||||
### Supplementary Items
|
||||
- item_name: Brief explanation (why it should be added)
|
||||
...
|
||||
|
||||
### Recommended Supplementary Fields
|
||||
- field_name: Field description (why this dimension is needed)
|
||||
...
|
||||
|
||||
### Sources
|
||||
- [Source1](url1)
|
||||
- [Source2](url2)
|
||||
"""
|
||||
```
|
||||
|
||||
**One-shot Example** (assuming researching AI Coding History):
|
||||
```
|
||||
## Task
|
||||
Research topic: AI Coding History
|
||||
Current date: 2025-12-30
|
||||
|
||||
Based on the following initial framework, supplement latest items and recommended research fields.
|
||||
|
||||
## Existing Framework
|
||||
### Items List
|
||||
1. GitHub Copilot: Developed by Microsoft/GitHub, first mainstream AI coding assistant
|
||||
2. Cursor: AI-first IDE, based on VSCode
|
||||
...
|
||||
|
||||
### Field Framework
|
||||
- Basic Info: name, release_date, company
|
||||
- Technical Features: underlying_model, context_window
|
||||
...
|
||||
|
||||
## Goals
|
||||
1. Verify if existing items are missing important objects
|
||||
2. Supplement items based on missing objects
|
||||
3. Continue searching for AI Coding History related items within since 2024 and supplement
|
||||
4. Supplement new fields
|
||||
|
||||
## Output Requirements
|
||||
Return structured results directly (do not write files):
|
||||
|
||||
### Supplementary Items
|
||||
- item_name: Brief explanation (why it should be added)
|
||||
...
|
||||
|
||||
### Recommended Supplementary Fields
|
||||
- field_name: Field description (why this dimension is needed)
|
||||
...
|
||||
|
||||
### Sources
|
||||
- [Source1](url1)
|
||||
- [Source2](url2)
|
||||
```
|
||||
|
||||
### Step 3: Ask User for Existing Fields
|
||||
Use request_user_input to ask if user has existing field definition file, if so read and merge.
|
||||
|
||||
### Step 4: Generate Outline (Separate Files)
|
||||
Merge {step1_output}, {step2_output} and user's existing fields, generate two files:
|
||||
|
||||
**outline.yaml** (items + config):
|
||||
- topic: Research topic
|
||||
- items: Research objects list
|
||||
- execution:
|
||||
- batch_size: Number of parallel agents (confirm with request_user_input)
|
||||
- items_per_agent: Items per agent (confirm with request_user_input)
|
||||
- output_dir: Results output directory (default: ./results)
|
||||
|
||||
**fields.yaml** (field definitions):
|
||||
- Field categories and definitions
|
||||
- Each field's name, description, detail_level
|
||||
- detail_level hierarchy: brief -> moderate -> detailed
|
||||
- uncertain: Uncertain fields list (reserved field, auto-filled in deep phase)
|
||||
|
||||
### Step 5: Output and Confirm
|
||||
- Create directory: `./{topic_slug}/`
|
||||
- Save: `outline.yaml` and `fields.yaml`
|
||||
- Show to user for confirmation
|
||||
|
||||
## Output Path
|
||||
```
|
||||
{current_working_directory}/{topic_slug}/
|
||||
├── outline.yaml # items list + execution config
|
||||
└── fields.yaml # field definitions
|
||||
```
|
||||
|
||||
## Follow-up Commands
|
||||
- `/research-add-items` - Supplement items
|
||||
- `/research-add-fields` - Supplement fields
|
||||
- `/research-deep` - Start deep research
|
||||
@@ -0,0 +1,198 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import json
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
CATEGORY_MAPPING = {
|
||||
"basic_info": ["basic_info", "Basic Info"],
|
||||
"technical_features": ["technical_features", "technical_characteristics", "Technical Features"],
|
||||
"performance_metrics": ["performance_metrics", "performance", "Performance Metrics"],
|
||||
"milestone_significance": ["milestone_significance", "milestones", "Milestone Significance"],
|
||||
"business_info": ["business_info", "commercial_info", "Business Info"],
|
||||
"competition_ecosystem": ["competition_ecosystem", "competition", "Competition Ecosystem"],
|
||||
"history": ["history", "History"],
|
||||
"market_positioning": ["market_positioning", "market", "Market Positioning"],
|
||||
}
|
||||
|
||||
_SKIP_KEYS = {"_source_file", "uncertain"}
|
||||
|
||||
|
||||
def load_fields_yaml(fields_path):
|
||||
"""Parse fields.yaml in the single schema the research skills emit:
|
||||
|
||||
fields:
|
||||
<category>:
|
||||
- {name: ..., description: ..., detail_level: ...}
|
||||
...
|
||||
uncertain: []
|
||||
|
||||
This is the ONLY accepted shape. A fields.yaml that does not match fails
|
||||
loudly instead of silently passing with zero fields.
|
||||
|
||||
Required semantics (so the validator can never pass vacuously / "lie"):
|
||||
- if ANY field carries an explicit `required:` key -> opt-in, preserve it
|
||||
- else (detail_level-style, no markers) -> ALL fields required, because the
|
||||
script's stated purpose is COMPLETE field coverage.
|
||||
"""
|
||||
with fields_path.open(encoding="utf-8") as f:
|
||||
data = yaml.safe_load(f) or {}
|
||||
defs = [] # (name, category, required_or_None)
|
||||
|
||||
fn = data.get("fields")
|
||||
if not isinstance(fn, dict):
|
||||
print(f"[ERROR] fields.yaml must use the `fields: {{<category>: [{{name, ...}}]}}` shape; got {type(fn).__name__ if fn is not None else 'None'}.")
|
||||
sys.exit(1)
|
||||
|
||||
for cname, flist in fn.items():
|
||||
if cname in _SKIP_KEYS:
|
||||
continue
|
||||
if not isinstance(flist, list):
|
||||
print(f"[ERROR] category `{cname}` must map to a list of field dicts; got {type(flist).__name__}.")
|
||||
sys.exit(1)
|
||||
for field in flist:
|
||||
if isinstance(field, dict) and "name" in field:
|
||||
defs.append((str(field["name"]), str(cname), field.get("required", None)))
|
||||
else:
|
||||
print(f"[ERROR] field entry under `{cname}` must be a dict with a `name` key; got {field!r}.")
|
||||
sys.exit(1)
|
||||
|
||||
if not defs:
|
||||
print("[ERROR] fields.yaml parsed zero fields. Ensure at least one category with field dicts.")
|
||||
sys.exit(1)
|
||||
|
||||
all_fields = {n for n, _, _ in defs}
|
||||
if any(r is not None for _, _, r in defs):
|
||||
required_fields = {n for n, _, r in defs if r}
|
||||
else:
|
||||
required_fields = set(all_fields)
|
||||
field_categories = {n: c for n, c, _ in defs}
|
||||
return all_fields, required_fields, field_categories
|
||||
|
||||
|
||||
def extract_json_fields(data, category_mapping=None):
|
||||
category_mapping = CATEGORY_MAPPING if category_mapping is None else category_mapping
|
||||
nested_keys = {k for keys in category_mapping.values() for k in keys}
|
||||
fields = set()
|
||||
stack = [(data, True)]
|
||||
while stack:
|
||||
obj, is_category_level = stack.pop()
|
||||
if isinstance(obj, dict):
|
||||
for k, v in obj.items():
|
||||
if k in _SKIP_KEYS:
|
||||
continue
|
||||
if is_category_level and k in nested_keys:
|
||||
if isinstance(v, dict):
|
||||
stack.append((v, True))
|
||||
continue
|
||||
fields.add(k)
|
||||
elif isinstance(obj, list):
|
||||
stack.extend((item, is_category_level) for item in obj if isinstance(item, dict))
|
||||
return fields
|
||||
|
||||
|
||||
def validate_json(json_path, all_fields, required_fields, field_categories):
|
||||
with json_path.open(encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
json_fields = extract_json_fields(data)
|
||||
covered = all_fields & json_fields
|
||||
missing = all_fields - json_fields
|
||||
extra = json_fields - all_fields
|
||||
missing_required = missing & required_fields
|
||||
missing_by_category = defaultdict(list)
|
||||
for field in missing:
|
||||
missing_by_category[field_categories.get(field, "Unknown")].append(field)
|
||||
return {
|
||||
"file": json_path.name,
|
||||
"total_defined": len(all_fields),
|
||||
"covered": len(covered),
|
||||
"missing": len(missing),
|
||||
"extra": len(extra),
|
||||
"coverage_rate": len(covered) / len(all_fields) * 100 if all_fields else 100,
|
||||
"missing_required": sorted(missing_required),
|
||||
"missing_optional": sorted(missing - required_fields),
|
||||
"missing_by_category": {k: sorted(v) for k, v in missing_by_category.items()},
|
||||
"extra_fields": sorted(extra),
|
||||
"valid": len(missing_required) == 0,
|
||||
}
|
||||
|
||||
|
||||
def print_result(result, verbose=True):
|
||||
status = "PASS" if result["valid"] else "FAIL"
|
||||
line = "=" * 60
|
||||
print(f"\n{line}")
|
||||
print(f"[{status}] {result['file']}")
|
||||
print(line)
|
||||
print(f"Coverage: {result['coverage_rate']:.1f}% ({result['covered']}/{result['total_defined']})")
|
||||
if result["missing_required"]:
|
||||
print(f"\n[ERROR] Missing required fields ({len(result['missing_required'])}):")
|
||||
print("\n".join(f" - {f}" for f in result["missing_required"]))
|
||||
if verbose and result["missing_optional"]:
|
||||
missing_required = set(result["missing_required"])
|
||||
print(f"\n[WARN] Missing optional fields ({len(result['missing_optional'])}):")
|
||||
for cat in sorted(result["missing_by_category"]):
|
||||
optional = [f for f in result["missing_by_category"][cat] if f not in missing_required]
|
||||
if optional:
|
||||
print(f" [{cat}]: {', '.join(optional)}")
|
||||
if verbose and result["extra_fields"]:
|
||||
extra = result["extra_fields"]
|
||||
print(f"\n[INFO] Extra fields ({len(extra)}):")
|
||||
print(f" {', '.join(extra[:10])}")
|
||||
if len(extra) > 10:
|
||||
print(f" ... and {len(extra) - 10} more")
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser(description="Validate whether JSON files cover all fields defined in fields.yaml")
|
||||
parser.add_argument("--fields", "-f", type=str, help="Path to fields.yaml", default="fields.yaml")
|
||||
parser.add_argument("--json", "-j", type=str, nargs="*", help="JSON file paths to validate")
|
||||
parser.add_argument("--dir", "-d", type=str, help="Directory containing JSON files", default="results")
|
||||
parser.add_argument("--quiet", "-q", action="store_true", help="Show summary only")
|
||||
args = parser.parse_args()
|
||||
fields_path = Path(args.fields)
|
||||
if not fields_path.exists():
|
||||
for p in (Path.cwd() / "fields.yaml", Path.cwd().parent / "fields.yaml"):
|
||||
if p.exists():
|
||||
fields_path = p
|
||||
break
|
||||
if not fields_path.exists():
|
||||
print(f"[ERROR] fields.yaml not found: {fields_path}")
|
||||
sys.exit(1)
|
||||
print(f"Field definition file: {fields_path}")
|
||||
all_fields, required_fields, field_categories = load_fields_yaml(fields_path)
|
||||
print(f"Total fields: {len(all_fields)} (required: {len(required_fields)}, optional: {len(all_fields) - len(required_fields)})")
|
||||
json_files = (
|
||||
[Path(p) for p in args.json]
|
||||
if args.json
|
||||
else sorted(Path(args.dir).glob("*.json")) if Path(args.dir).exists() else []
|
||||
)
|
||||
if not json_files:
|
||||
print("[WARN] No JSON files found")
|
||||
sys.exit(0)
|
||||
results = []
|
||||
for json_path in json_files:
|
||||
if not json_path.exists():
|
||||
print(f"[WARN] File not found: {json_path}")
|
||||
continue
|
||||
result = validate_json(json_path, all_fields, required_fields, field_categories)
|
||||
results.append(result)
|
||||
print_result(result, verbose=not args.quiet)
|
||||
line = "=" * 60
|
||||
print(f"\n{line}")
|
||||
print("Summary")
|
||||
print(line)
|
||||
passed = sum(1 for r in results if r["valid"])
|
||||
avg_coverage = sum(r["coverage_rate"] for r in results) / len(results) if results else 0
|
||||
print(f"Validation passed: {passed}/{len(results)}")
|
||||
print(f"Average coverage: {avg_coverage:.1f}%")
|
||||
if passed < len(results):
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
name: research-add-fields
|
||||
description: Add field definitions to existing research outline.
|
||||
---
|
||||
|
||||
# Research Add Fields - Supplement Research Fields
|
||||
|
||||
## Trigger
|
||||
`/research-add-fields`
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Auto-locate Fields File
|
||||
Find `*/fields.yaml` file in current working directory, auto-read existing fields definitions.
|
||||
|
||||
### Step 2: Get Supplement Source
|
||||
Ask user to choose:
|
||||
- **A. User direct input**: User provides field names and descriptions
|
||||
- **B. Web Search**: Launch agent to search common fields in this domain
|
||||
|
||||
### Step 3: Display and Confirm
|
||||
- Display suggested new fields list
|
||||
- User confirms which fields to add
|
||||
- User specifies field category and detail_level
|
||||
|
||||
### Step 4: Save Update
|
||||
Append confirmed fields to fields.yaml, save file.
|
||||
|
||||
## Output
|
||||
Updated `{topic}/fields.yaml` file (in-place modification, requires user confirmation)
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
name: research-add-items
|
||||
description: Add items (research objects) to existing research outline.
|
||||
---
|
||||
|
||||
# Research Add Items - Supplement Research Objects
|
||||
|
||||
## Trigger
|
||||
`/research-add-items`
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Auto-locate Outline
|
||||
Find `*/outline.yaml` file in current working directory, auto-read.
|
||||
|
||||
### Step 2: Get Supplement Sources in Parallel
|
||||
Simultaneously:
|
||||
- **A. Ask user**: What items to supplement? Any specific names?
|
||||
- **B. Ask if Web Search needed**: Launch agent to search for more items?
|
||||
|
||||
### Step 3: Merge and Update
|
||||
- Append new items to outline.yaml
|
||||
- Display to user for confirmation
|
||||
- Avoid duplicates
|
||||
- Save updated outline
|
||||
|
||||
## Output
|
||||
Updated `{topic}/outline.yaml` file (in-place modification)
|
||||
@@ -0,0 +1,98 @@
|
||||
---
|
||||
name: research-deep
|
||||
description: Read research outline, launch independent agent for each item for deep research. Disable task output.
|
||||
---
|
||||
|
||||
# Research Deep - Deep Research
|
||||
|
||||
## Trigger
|
||||
`/research-deep`
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Auto-locate Outline
|
||||
Find `*/outline.yaml` file in current working directory, read items list, execution config (including items_per_agent).
|
||||
|
||||
### Step 2: Resume Check
|
||||
- Check completed JSON files in output_dir
|
||||
- Skip completed items
|
||||
|
||||
### Step 3: Batch Execution
|
||||
- Batch by batch_size (need user approval before next batch)
|
||||
- Each agent handles items_per_agent items
|
||||
- Launch web-search-agent (background parallel, disable task output)
|
||||
|
||||
**Parameter Retrieval**:
|
||||
- `{topic}`: topic field from outline.yaml
|
||||
- `{item_name}`: item's name field
|
||||
- `{item_related_info}`: item's complete yaml content (name + category + description etc.)
|
||||
- `{output_dir}`: execution.output_dir from outline.yaml (default: ./results)
|
||||
- `{fields_path}`: absolute path to {topic}/fields.yaml
|
||||
- `{output_path}`: absolute path to {output_dir}/{item_name_slug}.json (slugify item_name: replace spaces with _, remove special chars)
|
||||
|
||||
**Hard Constraint**: The following prompt must be strictly reproduced, only replacing variables in {xxx}, do not modify structure or wording.
|
||||
|
||||
**Prompt Template**:
|
||||
```python
|
||||
prompt = f"""## Task
|
||||
Research {item_related_info}, output structured JSON to {output_path}
|
||||
|
||||
## Field Definitions
|
||||
Read {fields_path} to get all field definitions
|
||||
|
||||
## Output Requirements
|
||||
1. Output JSON according to fields defined in fields.yaml
|
||||
2. Mark uncertain field values with [uncertain]
|
||||
3. Add uncertain array at the end of JSON, listing all uncertain field names
|
||||
4. All field values must be in English
|
||||
|
||||
## Output Path
|
||||
{output_path}
|
||||
|
||||
## Validation
|
||||
After completing JSON output, run validation script to ensure complete field coverage:
|
||||
python ~/.codex/skills/research/validate_json.py -f {fields_path} -j {output_path}
|
||||
Task is complete only after validation passes.
|
||||
"""
|
||||
```
|
||||
|
||||
**One-shot Example** (assuming researching GitHub Copilot):
|
||||
```
|
||||
## Task
|
||||
Research name: GitHub Copilot
|
||||
category: International Product
|
||||
description: Developed by Microsoft/GitHub, first mainstream AI coding assistant, ~40% market share, output structured JSON to {project_dir}/results/GitHub_Copilot.json
|
||||
|
||||
## Field Definitions
|
||||
Read {project_dir}/fields.yaml to get all field definitions
|
||||
|
||||
## Output Requirements
|
||||
1. Output JSON according to fields defined in fields.yaml
|
||||
2. Mark uncertain field values with [uncertain]
|
||||
3. Add uncertain array at the end of JSON, listing all uncertain field names
|
||||
4. All field values must be in English
|
||||
|
||||
## Output Path
|
||||
{project_dir}/results/GitHub_Copilot.json
|
||||
|
||||
## Validation
|
||||
After completing JSON output, run validation script to ensure complete field coverage:
|
||||
python ~/.codex/skills/research/validate_json.py -f {project_dir}/fields.yaml -j {project_dir}/results/GitHub_Copilot.json
|
||||
Task is complete only after validation passes.
|
||||
```
|
||||
|
||||
### Step 4: Wait and Monitor
|
||||
- Wait for current batch to complete
|
||||
- Launch next batch
|
||||
- Display progress
|
||||
|
||||
### Step 5: Summary Report
|
||||
After all complete, output:
|
||||
- Completion count
|
||||
- Failed/uncertain marked items
|
||||
- Output directory
|
||||
|
||||
## Agent Config
|
||||
- Background execution: Yes
|
||||
- Task Output: Disabled (agent has explicit output file when complete)
|
||||
- Resume support: Yes
|
||||
@@ -0,0 +1,91 @@
|
||||
---
|
||||
name: research-report
|
||||
description: Summarize deep research results into markdown report, cover all fields, skip uncertain values.
|
||||
---
|
||||
|
||||
# Research Report - Summary Report
|
||||
|
||||
## Trigger
|
||||
`/research-report`
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Locate Results Directory
|
||||
Find `*/outline.yaml` in current working directory, read topic and output_dir config.
|
||||
|
||||
### Step 2: Scan Optional Summary Fields
|
||||
Read all JSON results, extract fields suitable for TOC display (numeric, short metrics), e.g.:
|
||||
- github_stars
|
||||
- google_scholar_cites
|
||||
- swe_bench_score
|
||||
- user_scale
|
||||
- valuation
|
||||
- release_date
|
||||
|
||||
Use request_user_input to ask user:
|
||||
- Which fields to display in TOC besides item name?
|
||||
- Provide dynamic options list (based on actual fields in JSON)
|
||||
|
||||
### Step 3: Generate Python Conversion Script
|
||||
Generate `generate_report.py` in `{topic}/` directory, script requirements:
|
||||
- Read all JSON from output_dir
|
||||
- Read fields.yaml to get field structure
|
||||
- Cover all field values from each JSON
|
||||
- Skip fields with values containing [uncertain]
|
||||
- Skip fields listed in uncertain array
|
||||
- Generate markdown report format: Table of contents (with anchor links + user-selected summary fields) + Detailed content (by field category)
|
||||
- Save to `{topic}/report.md`
|
||||
|
||||
**TOC Format Requirements**:
|
||||
- Must include every item
|
||||
- Each item displays: number, name (anchor link), user-selected summary fields
|
||||
- Example: `1. [GitHub Copilot](#github-copilot) - Stars: 10k | Score: 85%`
|
||||
|
||||
#### Script Technical Requirements (Must Follow)
|
||||
|
||||
**1. JSON Structure Compatibility**
|
||||
Support two JSON structures:
|
||||
- Flat structure: Fields directly at top level `{"name": "xxx", "release_date": "xxx"}`
|
||||
- Nested structure: Fields in category sub-dict `{"basic_info": {"name": "xxx"}, "technical_features": {...}}`
|
||||
|
||||
Field lookup order: Top level -> category mapping key -> Traverse all nested dicts
|
||||
|
||||
**2. Category Multi-language Mapping**
|
||||
fields.yaml category names and JSON keys can be any combination (CN-CN, CN-EN, EN-CN, EN-EN). Must establish bidirectional mapping:
|
||||
```python
|
||||
CATEGORY_MAPPING = {
|
||||
"Basic Info": ["basic_info", "Basic Info"],
|
||||
"Technical Features": ["technical_features", "technical_characteristics", "Technical Features"],
|
||||
"Performance Metrics": ["performance_metrics", "performance", "Performance Metrics"],
|
||||
"Milestone Significance": ["milestone_significance", "milestones", "Milestone Significance"],
|
||||
"Business Info": ["business_info", "commercial_info", "Business Info"],
|
||||
"Competition & Ecosystem": ["competition_ecosystem", "competition", "Competition & Ecosystem"],
|
||||
"History": ["history", "History"],
|
||||
"Market Positioning": ["market_positioning", "market", "Market Positioning"],
|
||||
}
|
||||
```
|
||||
|
||||
**3. Complex Value Formatting**
|
||||
- list of dicts (e.g., key_events, funding_history): Format each dict as one line, separate kv with ` | `
|
||||
- Normal list: Short lists joined with comma, long lists displayed with line breaks
|
||||
- Nested dict: Recursive formatting, display with semicolon or line breaks
|
||||
- Long text strings (over 100 chars): Add line breaks `<br>` or use blockquote format for readability
|
||||
|
||||
**4. Extra Fields Collection**
|
||||
Collect fields that exist in JSON but not defined in fields.yaml, put in "Other Info" category. Note to filter:
|
||||
- Internal fields: `_source_file`, `uncertain`
|
||||
- Nested structure top-level keys: `basic_info`, `technical_features` etc.
|
||||
- `uncertain` array: Display each field name on separate line, don't compress into one line
|
||||
|
||||
**5. Uncertain Value Skipping**
|
||||
Skip conditions:
|
||||
- Field value contains `[uncertain]` string
|
||||
- Field name is in `uncertain` array
|
||||
- Field value is None or empty string
|
||||
|
||||
### Step 4: Execute Script
|
||||
Run `python {topic}/generate_report.py`
|
||||
|
||||
## Output
|
||||
- `{topic}/generate_report.py` - Conversion script
|
||||
- `{topic}/report.md` - Summary report
|
||||
@@ -0,0 +1,143 @@
|
||||
---
|
||||
name: research
|
||||
description: Conduct preliminary research on a topic and generate research outline. For academic research, benchmark research, technology selection, etc.
|
||||
---
|
||||
|
||||
# Research Skill - Preliminary Research
|
||||
|
||||
## Trigger
|
||||
`/research <topic>`
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Generate Initial Framework from Model Knowledge
|
||||
Based on topic, use model's existing knowledge to generate:
|
||||
- Main research objects/items list in this domain
|
||||
- Suggested research field framework
|
||||
|
||||
Output {step1_output}, use request_user_input to confirm:
|
||||
- Need to add/remove items?
|
||||
- Does field framework meet requirements?
|
||||
|
||||
### Step 2: Web Search Supplement
|
||||
Use request_user_input to ask for time range (e.g., last 6 months, since 2024, unlimited).
|
||||
|
||||
**Parameter Retrieval**:
|
||||
- `{topic}`: User input research topic
|
||||
- `{YYYY-MM-DD}`: Current date
|
||||
- `{step1_output}`: Complete output from Step 1
|
||||
- `{time_range}`: User specified time range
|
||||
|
||||
**Hard Constraint**: The following prompt must be strictly reproduced, only replacing variables in {xxx}, do not modify structure or wording.
|
||||
|
||||
Launch 1 web-search-agent (background), **Prompt Template**:
|
||||
```python
|
||||
prompt = f"""## Task
|
||||
Research topic: {topic}
|
||||
Current date: {YYYY-MM-DD}
|
||||
|
||||
Based on the following initial framework, supplement latest items and recommended research fields.
|
||||
|
||||
## Existing Framework
|
||||
{step1_output}
|
||||
|
||||
## Goals
|
||||
1. Verify if existing items are missing important objects
|
||||
2. Supplement items based on missing objects
|
||||
3. Continue searching for {topic} related items within {time_range} and supplement
|
||||
4. Supplement new fields
|
||||
|
||||
## Output Requirements
|
||||
Return structured results directly (do not write files):
|
||||
|
||||
### Supplementary Items
|
||||
- item_name: Brief explanation (why it should be added)
|
||||
...
|
||||
|
||||
### Recommended Supplementary Fields
|
||||
- field_name: Field description (why this dimension is needed)
|
||||
...
|
||||
|
||||
### Sources
|
||||
- [Source1](url1)
|
||||
- [Source2](url2)
|
||||
"""
|
||||
```
|
||||
|
||||
**One-shot Example** (assuming researching AI Coding History):
|
||||
```
|
||||
## Task
|
||||
Research topic: AI Coding History
|
||||
Current date: 2025-12-30
|
||||
|
||||
Based on the following initial framework, supplement latest items and recommended research fields.
|
||||
|
||||
## Existing Framework
|
||||
### Items List
|
||||
1. GitHub Copilot: Developed by Microsoft/GitHub, first mainstream AI coding assistant
|
||||
2. Cursor: AI-first IDE, based on VSCode
|
||||
...
|
||||
|
||||
### Field Framework
|
||||
- Basic Info: name, release_date, company
|
||||
- Technical Features: underlying_model, context_window
|
||||
...
|
||||
|
||||
## Goals
|
||||
1. Verify if existing items are missing important objects
|
||||
2. Supplement items based on missing objects
|
||||
3. Continue searching for AI Coding History related items within since 2024 and supplement
|
||||
4. Supplement new fields
|
||||
|
||||
## Output Requirements
|
||||
Return structured results directly (do not write files):
|
||||
|
||||
### Supplementary Items
|
||||
- item_name: Brief explanation (why it should be added)
|
||||
...
|
||||
|
||||
### Recommended Supplementary Fields
|
||||
- field_name: Field description (why this dimension is needed)
|
||||
...
|
||||
|
||||
### Sources
|
||||
- [Source1](url1)
|
||||
- [Source2](url2)
|
||||
```
|
||||
|
||||
### Step 3: Ask User for Existing Fields
|
||||
Use request_user_input to ask if user has existing field definition file, if so read and merge.
|
||||
|
||||
### Step 4: Generate Outline (Separate Files)
|
||||
Merge {step1_output}, {step2_output} and user's existing fields, generate two files:
|
||||
|
||||
**outline.yaml** (items + config):
|
||||
- topic: Research topic
|
||||
- items: Research objects list
|
||||
- execution:
|
||||
- batch_size: Number of parallel agents (confirm with request_user_input)
|
||||
- items_per_agent: Items per agent (confirm with request_user_input)
|
||||
- output_dir: Results output directory (default: ./results)
|
||||
|
||||
**fields.yaml** (field definitions):
|
||||
- Field categories and definitions
|
||||
- Each field's name, description, detail_level
|
||||
- detail_level hierarchy: brief -> moderate -> detailed
|
||||
- uncertain: Uncertain fields list (reserved field, auto-filled in deep phase)
|
||||
|
||||
### Step 5: Output and Confirm
|
||||
- Create directory: `./{topic_slug}/`
|
||||
- Save: `outline.yaml` and `fields.yaml`
|
||||
- Show to user for confirmation
|
||||
|
||||
## Output Path
|
||||
```
|
||||
{current_working_directory}/{topic_slug}/
|
||||
├── outline.yaml # items list + execution config
|
||||
└── fields.yaml # field definitions
|
||||
```
|
||||
|
||||
## Follow-up Commands
|
||||
- `/research-add-items` - Supplement items
|
||||
- `/research-add-fields` - Supplement fields
|
||||
- `/research-deep` - Start deep research
|
||||
@@ -0,0 +1,198 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import json
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
CATEGORY_MAPPING = {
|
||||
"basic_info": ["basic_info", "Basic Info"],
|
||||
"technical_features": ["technical_features", "technical_characteristics", "Technical Features"],
|
||||
"performance_metrics": ["performance_metrics", "performance", "Performance Metrics"],
|
||||
"milestone_significance": ["milestone_significance", "milestones", "Milestone Significance"],
|
||||
"business_info": ["business_info", "commercial_info", "Business Info"],
|
||||
"competition_ecosystem": ["competition_ecosystem", "competition", "Competition Ecosystem"],
|
||||
"history": ["history", "History"],
|
||||
"market_positioning": ["market_positioning", "market", "Market Positioning"],
|
||||
}
|
||||
|
||||
_SKIP_KEYS = {"_source_file", "uncertain"}
|
||||
|
||||
|
||||
def load_fields_yaml(fields_path):
|
||||
"""Parse fields.yaml in the single schema the research skills emit:
|
||||
|
||||
fields:
|
||||
<category>:
|
||||
- {name: ..., description: ..., detail_level: ...}
|
||||
...
|
||||
uncertain: []
|
||||
|
||||
This is the ONLY accepted shape. A fields.yaml that does not match fails
|
||||
loudly instead of silently passing with zero fields.
|
||||
|
||||
Required semantics (so the validator can never pass vacuously / "lie"):
|
||||
- if ANY field carries an explicit `required:` key -> opt-in, preserve it
|
||||
- else (detail_level-style, no markers) -> ALL fields required, because the
|
||||
script's stated purpose is COMPLETE field coverage.
|
||||
"""
|
||||
with fields_path.open(encoding="utf-8") as f:
|
||||
data = yaml.safe_load(f) or {}
|
||||
defs = [] # (name, category, required_or_None)
|
||||
|
||||
fn = data.get("fields")
|
||||
if not isinstance(fn, dict):
|
||||
print(f"[ERROR] fields.yaml must use the `fields: {{<category>: [{{name, ...}}]}}` shape; got {type(fn).__name__ if fn is not None else 'None'}.")
|
||||
sys.exit(1)
|
||||
|
||||
for cname, flist in fn.items():
|
||||
if cname in _SKIP_KEYS:
|
||||
continue
|
||||
if not isinstance(flist, list):
|
||||
print(f"[ERROR] category `{cname}` must map to a list of field dicts; got {type(flist).__name__}.")
|
||||
sys.exit(1)
|
||||
for field in flist:
|
||||
if isinstance(field, dict) and "name" in field:
|
||||
defs.append((str(field["name"]), str(cname), field.get("required", None)))
|
||||
else:
|
||||
print(f"[ERROR] field entry under `{cname}` must be a dict with a `name` key; got {field!r}.")
|
||||
sys.exit(1)
|
||||
|
||||
if not defs:
|
||||
print("[ERROR] fields.yaml parsed zero fields. Ensure at least one category with field dicts.")
|
||||
sys.exit(1)
|
||||
|
||||
all_fields = {n for n, _, _ in defs}
|
||||
if any(r is not None for _, _, r in defs):
|
||||
required_fields = {n for n, _, r in defs if r}
|
||||
else:
|
||||
required_fields = set(all_fields)
|
||||
field_categories = {n: c for n, c, _ in defs}
|
||||
return all_fields, required_fields, field_categories
|
||||
|
||||
|
||||
def extract_json_fields(data, category_mapping=None):
|
||||
category_mapping = CATEGORY_MAPPING if category_mapping is None else category_mapping
|
||||
nested_keys = {k for keys in category_mapping.values() for k in keys}
|
||||
fields = set()
|
||||
stack = [(data, True)]
|
||||
while stack:
|
||||
obj, is_category_level = stack.pop()
|
||||
if isinstance(obj, dict):
|
||||
for k, v in obj.items():
|
||||
if k in _SKIP_KEYS:
|
||||
continue
|
||||
if is_category_level and k in nested_keys:
|
||||
if isinstance(v, dict):
|
||||
stack.append((v, True))
|
||||
continue
|
||||
fields.add(k)
|
||||
elif isinstance(obj, list):
|
||||
stack.extend((item, is_category_level) for item in obj if isinstance(item, dict))
|
||||
return fields
|
||||
|
||||
|
||||
def validate_json(json_path, all_fields, required_fields, field_categories):
|
||||
with json_path.open(encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
json_fields = extract_json_fields(data)
|
||||
covered = all_fields & json_fields
|
||||
missing = all_fields - json_fields
|
||||
extra = json_fields - all_fields
|
||||
missing_required = missing & required_fields
|
||||
missing_by_category = defaultdict(list)
|
||||
for field in missing:
|
||||
missing_by_category[field_categories.get(field, "Unknown")].append(field)
|
||||
return {
|
||||
"file": json_path.name,
|
||||
"total_defined": len(all_fields),
|
||||
"covered": len(covered),
|
||||
"missing": len(missing),
|
||||
"extra": len(extra),
|
||||
"coverage_rate": len(covered) / len(all_fields) * 100 if all_fields else 100,
|
||||
"missing_required": sorted(missing_required),
|
||||
"missing_optional": sorted(missing - required_fields),
|
||||
"missing_by_category": {k: sorted(v) for k, v in missing_by_category.items()},
|
||||
"extra_fields": sorted(extra),
|
||||
"valid": len(missing_required) == 0,
|
||||
}
|
||||
|
||||
|
||||
def print_result(result, verbose=True):
|
||||
status = "PASS" if result["valid"] else "FAIL"
|
||||
line = "=" * 60
|
||||
print(f"\n{line}")
|
||||
print(f"[{status}] {result['file']}")
|
||||
print(line)
|
||||
print(f"Coverage: {result['coverage_rate']:.1f}% ({result['covered']}/{result['total_defined']})")
|
||||
if result["missing_required"]:
|
||||
print(f"\n[ERROR] Missing required fields ({len(result['missing_required'])}):")
|
||||
print("\n".join(f" - {f}" for f in result["missing_required"]))
|
||||
if verbose and result["missing_optional"]:
|
||||
missing_required = set(result["missing_required"])
|
||||
print(f"\n[WARN] Missing optional fields ({len(result['missing_optional'])}):")
|
||||
for cat in sorted(result["missing_by_category"]):
|
||||
optional = [f for f in result["missing_by_category"][cat] if f not in missing_required]
|
||||
if optional:
|
||||
print(f" [{cat}]: {', '.join(optional)}")
|
||||
if verbose and result["extra_fields"]:
|
||||
extra = result["extra_fields"]
|
||||
print(f"\n[INFO] Extra fields ({len(extra)}):")
|
||||
print(f" {', '.join(extra[:10])}")
|
||||
if len(extra) > 10:
|
||||
print(f" ... and {len(extra) - 10} more")
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser(description="Validate whether JSON files cover all fields defined in fields.yaml")
|
||||
parser.add_argument("--fields", "-f", type=str, help="Path to fields.yaml", default="fields.yaml")
|
||||
parser.add_argument("--json", "-j", type=str, nargs="*", help="JSON file paths to validate")
|
||||
parser.add_argument("--dir", "-d", type=str, help="Directory containing JSON files", default="results")
|
||||
parser.add_argument("--quiet", "-q", action="store_true", help="Show summary only")
|
||||
args = parser.parse_args()
|
||||
fields_path = Path(args.fields)
|
||||
if not fields_path.exists():
|
||||
for p in (Path.cwd() / "fields.yaml", Path.cwd().parent / "fields.yaml"):
|
||||
if p.exists():
|
||||
fields_path = p
|
||||
break
|
||||
if not fields_path.exists():
|
||||
print(f"[ERROR] fields.yaml not found: {fields_path}")
|
||||
sys.exit(1)
|
||||
print(f"Field definition file: {fields_path}")
|
||||
all_fields, required_fields, field_categories = load_fields_yaml(fields_path)
|
||||
print(f"Total fields: {len(all_fields)} (required: {len(required_fields)}, optional: {len(all_fields) - len(required_fields)})")
|
||||
json_files = (
|
||||
[Path(p) for p in args.json]
|
||||
if args.json
|
||||
else sorted(Path(args.dir).glob("*.json")) if Path(args.dir).exists() else []
|
||||
)
|
||||
if not json_files:
|
||||
print("[WARN] No JSON files found")
|
||||
sys.exit(0)
|
||||
results = []
|
||||
for json_path in json_files:
|
||||
if not json_path.exists():
|
||||
print(f"[WARN] File not found: {json_path}")
|
||||
continue
|
||||
result = validate_json(json_path, all_fields, required_fields, field_categories)
|
||||
results.append(result)
|
||||
print_result(result, verbose=not args.quiet)
|
||||
line = "=" * 60
|
||||
print(f"\n{line}")
|
||||
print("Summary")
|
||||
print(line)
|
||||
passed = sum(1 for r in results if r["valid"])
|
||||
avg_coverage = sum(r["coverage_rate"] for r in results) / len(results) if results else 0
|
||||
print(f"Validation passed: {passed}/{len(results)}")
|
||||
print(f"Average coverage: {avg_coverage:.1f}%")
|
||||
if passed < len(results):
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
name: research-add-fields
|
||||
user-invocable: true
|
||||
description: Add field definitions to existing research outline.
|
||||
allowed-tools: Bash, Read, Write, Glob, WebSearch, Task, AskUserQuestion
|
||||
---
|
||||
|
||||
# Research Add Fields - Supplement Research Fields
|
||||
|
||||
## Trigger
|
||||
`/research-add-fields`
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Auto-locate Fields File
|
||||
Find `*/fields.yaml` file in current working directory, auto-read existing fields definitions.
|
||||
|
||||
### Step 2: Get Supplement Source
|
||||
Ask user to choose:
|
||||
- **A. User direct input**: User provides field names and descriptions
|
||||
- **B. Web Search**: Launch agent to search common fields in this domain
|
||||
|
||||
### Step 3: Display and Confirm
|
||||
- Display suggested new fields list
|
||||
- User confirms which fields to add
|
||||
- User specifies field category and detail_level
|
||||
|
||||
### Step 4: Save Update
|
||||
Append confirmed fields to fields.yaml, save file.
|
||||
|
||||
## Output
|
||||
Updated `{topic}/fields.yaml` file (in-place modification, requires user confirmation)
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
name: research-add-items
|
||||
user-invocable: true
|
||||
description: Add items (research objects) to existing research outline.
|
||||
allowed-tools: Bash, Read, Write, Glob, WebSearch, Task, AskUserQuestion
|
||||
---
|
||||
|
||||
# Research Add Items - Supplement Research Objects
|
||||
|
||||
## Trigger
|
||||
`/research-add-items`
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Auto-locate Outline
|
||||
Find `*/outline.yaml` file in current working directory, auto-read.
|
||||
|
||||
### Step 2: Get Supplement Sources in Parallel
|
||||
Simultaneously:
|
||||
- **A. Ask user**: What items to supplement? Any specific names?
|
||||
- **B. Ask if Web Search needed**: Launch agent to search for more items?
|
||||
|
||||
### Step 3: Merge and Update
|
||||
- Append new items to outline.yaml
|
||||
- Display to user for confirmation
|
||||
- Avoid duplicates
|
||||
- Save updated outline
|
||||
|
||||
## Output
|
||||
Updated `{topic}/outline.yaml` file (in-place modification)
|
||||
@@ -0,0 +1,100 @@
|
||||
---
|
||||
name: research-deep
|
||||
user-invocable: true
|
||||
description: Read research outline, launch independent agent for each item for deep research. Disable task output.
|
||||
allowed-tools: Bash, Read, Write, Glob, WebSearch, Task
|
||||
---
|
||||
|
||||
# Research Deep - Deep Research
|
||||
|
||||
## Trigger
|
||||
`/research-deep`
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Auto-locate Outline
|
||||
Find `*/outline.yaml` file in current working directory, read items list, execution config (including items_per_agent).
|
||||
|
||||
### Step 2: Resume Check
|
||||
- Check completed JSON files in output_dir
|
||||
- Skip completed items
|
||||
|
||||
### Step 3: Batch Execution
|
||||
- Batch by batch_size (need user approval before next batch)
|
||||
- Each agent handles items_per_agent items
|
||||
- Launch web-search-agent (background parallel, disable task output)
|
||||
|
||||
**Parameter Retrieval**:
|
||||
- `{topic}`: topic field from outline.yaml
|
||||
- `{item_name}`: item's name field
|
||||
- `{item_related_info}`: item's complete yaml content (name + category + description etc.)
|
||||
- `{output_dir}`: execution.output_dir from outline.yaml (default: ./results)
|
||||
- `{fields_path}`: absolute path to {topic}/fields.yaml
|
||||
- `{output_path}`: absolute path to {output_dir}/{item_name_slug}.json (slugify item_name: replace spaces with _, remove special chars)
|
||||
|
||||
**Hard Constraint**: The following prompt must be strictly reproduced, only replacing variables in {xxx}, do not modify structure or wording.
|
||||
|
||||
**Prompt Template**:
|
||||
```python
|
||||
prompt = f"""## Task
|
||||
Research {item_related_info}, output structured JSON to {output_path}
|
||||
|
||||
## Field Definitions
|
||||
Read {fields_path} to get all field definitions
|
||||
|
||||
## Output Requirements
|
||||
1. Output JSON according to fields defined in fields.yaml
|
||||
2. Mark uncertain field values with [uncertain]
|
||||
3. Add uncertain array at the end of JSON, listing all uncertain field names
|
||||
4. All field values must be in English
|
||||
|
||||
## Output Path
|
||||
{output_path}
|
||||
|
||||
## Validation
|
||||
After completing JSON output, run validation script to ensure complete field coverage:
|
||||
python ~/.claude/skills/research/validate_json.py -f {fields_path} -j {output_path}
|
||||
Task is complete only after validation passes.
|
||||
"""
|
||||
```
|
||||
|
||||
**One-shot Example** (assuming researching GitHub Copilot):
|
||||
```
|
||||
## Task
|
||||
Research name: GitHub Copilot
|
||||
category: International Product
|
||||
description: Developed by Microsoft/GitHub, first mainstream AI coding assistant, ~40% market share, output structured JSON to {project_dir}/results/GitHub_Copilot.json
|
||||
|
||||
## Field Definitions
|
||||
Read {project_dir}/fields.yaml to get all field definitions
|
||||
|
||||
## Output Requirements
|
||||
1. Output JSON according to fields defined in fields.yaml
|
||||
2. Mark uncertain field values with [uncertain]
|
||||
3. Add uncertain array at the end of JSON, listing all uncertain field names
|
||||
4. All field values must be in English
|
||||
|
||||
## Output Path
|
||||
{project_dir}/results/GitHub_Copilot.json
|
||||
|
||||
## Validation
|
||||
After completing JSON output, run validation script to ensure complete field coverage:
|
||||
python ~/.claude/skills/research/validate_json.py -f {project_dir}/fields.yaml -j {project_dir}/results/GitHub_Copilot.json
|
||||
Task is complete only after validation passes.
|
||||
```
|
||||
|
||||
### Step 4: Wait and Monitor
|
||||
- Wait for current batch to complete
|
||||
- Launch next batch
|
||||
- Display progress
|
||||
|
||||
### Step 5: Summary Report
|
||||
After all complete, output:
|
||||
- Completion count
|
||||
- Failed/uncertain marked items
|
||||
- Output directory
|
||||
|
||||
## Agent Config
|
||||
- Background execution: Yes
|
||||
- Task Output: Disabled (agent has explicit output file when complete)
|
||||
- Resume support: Yes
|
||||
@@ -0,0 +1,93 @@
|
||||
---
|
||||
name: research-report
|
||||
user-invocable: true
|
||||
description: Summarize deep research results into markdown report, cover all fields, skip uncertain values.
|
||||
allowed-tools: Read, Write, Glob, Bash, AskUserQuestion
|
||||
---
|
||||
|
||||
# Research Report - Summary Report
|
||||
|
||||
## Trigger
|
||||
`/research-report`
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Locate Results Directory
|
||||
Find `*/outline.yaml` in current working directory, read topic and output_dir config.
|
||||
|
||||
### Step 2: Scan Optional Summary Fields
|
||||
Read all JSON results, extract fields suitable for TOC display (numeric, short metrics), e.g.:
|
||||
- github_stars
|
||||
- google_scholar_cites
|
||||
- swe_bench_score
|
||||
- user_scale
|
||||
- valuation
|
||||
- release_date
|
||||
|
||||
Use AskUserQuestion to ask user:
|
||||
- Which fields to display in TOC besides item name?
|
||||
- Provide dynamic options list (based on actual fields in JSON)
|
||||
|
||||
### Step 3: Generate Python Conversion Script
|
||||
Generate `generate_report.py` in `{topic}/` directory, script requirements:
|
||||
- Read all JSON from output_dir
|
||||
- Read fields.yaml to get field structure
|
||||
- Cover all field values from each JSON
|
||||
- Skip fields with values containing [uncertain]
|
||||
- Skip fields listed in uncertain array
|
||||
- Generate markdown report format: Table of contents (with anchor links + user-selected summary fields) + Detailed content (by field category)
|
||||
- Save to `{topic}/report.md`
|
||||
|
||||
**TOC Format Requirements**:
|
||||
- Must include every item
|
||||
- Each item displays: number, name (anchor link), user-selected summary fields
|
||||
- Example: `1. [GitHub Copilot](#github-copilot) - Stars: 10k | Score: 85%`
|
||||
|
||||
#### Script Technical Requirements (Must Follow)
|
||||
|
||||
**1. JSON Structure Compatibility**
|
||||
Support two JSON structures:
|
||||
- Flat structure: Fields directly at top level `{"name": "xxx", "release_date": "xxx"}`
|
||||
- Nested structure: Fields in category sub-dict `{"basic_info": {"name": "xxx"}, "technical_features": {...}}`
|
||||
|
||||
Field lookup order: Top level -> category mapping key -> Traverse all nested dicts
|
||||
|
||||
**2. Category Multi-language Mapping**
|
||||
fields.yaml category names and JSON keys can be any combination (CN-CN, CN-EN, EN-CN, EN-EN). Must establish bidirectional mapping:
|
||||
```python
|
||||
CATEGORY_MAPPING = {
|
||||
"Basic Info": ["basic_info", "Basic Info"],
|
||||
"Technical Features": ["technical_features", "technical_characteristics", "Technical Features"],
|
||||
"Performance Metrics": ["performance_metrics", "performance", "Performance Metrics"],
|
||||
"Milestone Significance": ["milestone_significance", "milestones", "Milestone Significance"],
|
||||
"Business Info": ["business_info", "commercial_info", "Business Info"],
|
||||
"Competition & Ecosystem": ["competition_ecosystem", "competition", "Competition & Ecosystem"],
|
||||
"History": ["history", "History"],
|
||||
"Market Positioning": ["market_positioning", "market", "Market Positioning"],
|
||||
}
|
||||
```
|
||||
|
||||
**3. Complex Value Formatting**
|
||||
- list of dicts (e.g., key_events, funding_history): Format each dict as one line, separate kv with ` | `
|
||||
- Normal list: Short lists joined with comma, long lists displayed with line breaks
|
||||
- Nested dict: Recursive formatting, display with semicolon or line breaks
|
||||
- Long text strings (over 100 chars): Add line breaks `<br>` or use blockquote format for readability
|
||||
|
||||
**4. Extra Fields Collection**
|
||||
Collect fields that exist in JSON but not defined in fields.yaml, put in "Other Info" category. Note to filter:
|
||||
- Internal fields: `_source_file`, `uncertain`
|
||||
- Nested structure top-level keys: `basic_info`, `technical_features` etc.
|
||||
- `uncertain` array: Display each field name on separate line, don't compress into one line
|
||||
|
||||
**5. Uncertain Value Skipping**
|
||||
Skip conditions:
|
||||
- Field value contains `[uncertain]` string
|
||||
- Field name is in `uncertain` array
|
||||
- Field value is None or empty string
|
||||
|
||||
### Step 4: Execute Script
|
||||
Run `python {topic}/generate_report.py`
|
||||
|
||||
## Output
|
||||
- `{topic}/generate_report.py` - Conversion script
|
||||
- `{topic}/report.md` - Summary report
|
||||
@@ -0,0 +1,145 @@
|
||||
---
|
||||
name: research
|
||||
user-invocable: true
|
||||
allowed-tools: Read, Write, Glob, WebSearch, Task, AskUserQuestion
|
||||
description: Conduct preliminary research on a topic and generate research outline. For academic research, benchmark research, technology selection, etc.
|
||||
---
|
||||
|
||||
# Research Skill - Preliminary Research
|
||||
|
||||
## Trigger
|
||||
`/research <topic>`
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Generate Initial Framework from Model Knowledge
|
||||
Based on topic, use model's existing knowledge to generate:
|
||||
- Main research objects/items list in this domain
|
||||
- Suggested research field framework
|
||||
|
||||
Output {step1_output}, use AskUserQuestion to confirm:
|
||||
- Need to add/remove items?
|
||||
- Does field framework meet requirements?
|
||||
|
||||
### Step 2: Web Search Supplement
|
||||
Use AskUserQuestion to ask for time range (e.g., last 6 months, since 2024, unlimited).
|
||||
|
||||
**Parameter Retrieval**:
|
||||
- `{topic}`: User input research topic
|
||||
- `{YYYY-MM-DD}`: Current date
|
||||
- `{step1_output}`: Complete output from Step 1
|
||||
- `{time_range}`: User specified time range
|
||||
|
||||
**Hard Constraint**: The following prompt must be strictly reproduced, only replacing variables in {xxx}, do not modify structure or wording.
|
||||
|
||||
Launch 1 web-search-agent (background), **Prompt Template**:
|
||||
```python
|
||||
prompt = f"""## Task
|
||||
Research topic: {topic}
|
||||
Current date: {YYYY-MM-DD}
|
||||
|
||||
Based on the following initial framework, supplement latest items and recommended research fields.
|
||||
|
||||
## Existing Framework
|
||||
{step1_output}
|
||||
|
||||
## Goals
|
||||
1. Verify if existing items are missing important objects
|
||||
2. Supplement items based on missing objects
|
||||
3. Continue searching for {topic} related items within {time_range} and supplement
|
||||
4. Supplement new fields
|
||||
|
||||
## Output Requirements
|
||||
Return structured results directly (do not write files):
|
||||
|
||||
### Supplementary Items
|
||||
- item_name: Brief explanation (why it should be added)
|
||||
...
|
||||
|
||||
### Recommended Supplementary Fields
|
||||
- field_name: Field description (why this dimension is needed)
|
||||
...
|
||||
|
||||
### Sources
|
||||
- [Source1](url1)
|
||||
- [Source2](url2)
|
||||
"""
|
||||
```
|
||||
|
||||
**One-shot Example** (assuming researching AI Coding History):
|
||||
```
|
||||
## Task
|
||||
Research topic: AI Coding History
|
||||
Current date: 2025-12-30
|
||||
|
||||
Based on the following initial framework, supplement latest items and recommended research fields.
|
||||
|
||||
## Existing Framework
|
||||
### Items List
|
||||
1. GitHub Copilot: Developed by Microsoft/GitHub, first mainstream AI coding assistant
|
||||
2. Cursor: AI-first IDE, based on VSCode
|
||||
...
|
||||
|
||||
### Field Framework
|
||||
- Basic Info: name, release_date, company
|
||||
- Technical Features: underlying_model, context_window
|
||||
...
|
||||
|
||||
## Goals
|
||||
1. Verify if existing items are missing important objects
|
||||
2. Supplement items based on missing objects
|
||||
3. Continue searching for AI Coding History related items within since 2024 and supplement
|
||||
4. Supplement new fields
|
||||
|
||||
## Output Requirements
|
||||
Return structured results directly (do not write files):
|
||||
|
||||
### Supplementary Items
|
||||
- item_name: Brief explanation (why it should be added)
|
||||
...
|
||||
|
||||
### Recommended Supplementary Fields
|
||||
- field_name: Field description (why this dimension is needed)
|
||||
...
|
||||
|
||||
### Sources
|
||||
- [Source1](url1)
|
||||
- [Source2](url2)
|
||||
```
|
||||
|
||||
### Step 3: Ask User for Existing Fields
|
||||
Use AskUserQuestion to ask if user has existing field definition file, if so read and merge.
|
||||
|
||||
### Step 4: Generate Outline (Separate Files)
|
||||
Merge {step1_output}, {step2_output} and user's existing fields, generate two files:
|
||||
|
||||
**outline.yaml** (items + config):
|
||||
- topic: Research topic
|
||||
- items: Research objects list
|
||||
- execution:
|
||||
- batch_size: Number of parallel agents (confirm with AskUserQuestion)
|
||||
- items_per_agent: Items per agent (confirm with AskUserQuestion)
|
||||
- output_dir: Results output directory (default: ./results)
|
||||
|
||||
**fields.yaml** (field definitions):
|
||||
- Field categories and definitions
|
||||
- Each field's name, description, detail_level
|
||||
- detail_level hierarchy: brief -> moderate -> detailed
|
||||
- uncertain: Uncertain fields list (reserved field, auto-filled in deep phase)
|
||||
|
||||
### Step 5: Output and Confirm
|
||||
- Create directory: `./{topic_slug}/`
|
||||
- Save: `outline.yaml` and `fields.yaml`
|
||||
- Show to user for confirmation
|
||||
|
||||
## Output Path
|
||||
```
|
||||
{current_working_directory}/{topic_slug}/
|
||||
├── outline.yaml # items list + execution config
|
||||
└── fields.yaml # field definitions
|
||||
```
|
||||
|
||||
## Follow-up Commands
|
||||
- `/research-add-items` - Supplement items
|
||||
- `/research-add-fields` - Supplement fields
|
||||
- `/research-deep` - Start deep research
|
||||
@@ -0,0 +1,198 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import json
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
CATEGORY_MAPPING = {
|
||||
"basic_info": ["basic_info", "Basic Info"],
|
||||
"technical_features": ["technical_features", "technical_characteristics", "Technical Features"],
|
||||
"performance_metrics": ["performance_metrics", "performance", "Performance Metrics"],
|
||||
"milestone_significance": ["milestone_significance", "milestones", "Milestone Significance"],
|
||||
"business_info": ["business_info", "commercial_info", "Business Info"],
|
||||
"competition_ecosystem": ["competition_ecosystem", "competition", "Competition Ecosystem"],
|
||||
"history": ["history", "History"],
|
||||
"market_positioning": ["market_positioning", "market", "Market Positioning"],
|
||||
}
|
||||
|
||||
_SKIP_KEYS = {"_source_file", "uncertain"}
|
||||
|
||||
|
||||
def load_fields_yaml(fields_path):
|
||||
"""Parse fields.yaml in the single schema the research skills emit:
|
||||
|
||||
fields:
|
||||
<category>:
|
||||
- {name: ..., description: ..., detail_level: ...}
|
||||
...
|
||||
uncertain: []
|
||||
|
||||
This is the ONLY accepted shape. A fields.yaml that does not match fails
|
||||
loudly instead of silently passing with zero fields.
|
||||
|
||||
Required semantics (so the validator can never pass vacuously / "lie"):
|
||||
- if ANY field carries an explicit `required:` key -> opt-in, preserve it
|
||||
- else (detail_level-style, no markers) -> ALL fields required, because the
|
||||
script's stated purpose is COMPLETE field coverage.
|
||||
"""
|
||||
with fields_path.open(encoding="utf-8") as f:
|
||||
data = yaml.safe_load(f) or {}
|
||||
defs = [] # (name, category, required_or_None)
|
||||
|
||||
fn = data.get("fields")
|
||||
if not isinstance(fn, dict):
|
||||
print(f"[ERROR] fields.yaml must use the `fields: {{<category>: [{{name, ...}}]}}` shape; got {type(fn).__name__ if fn is not None else 'None'}.")
|
||||
sys.exit(1)
|
||||
|
||||
for cname, flist in fn.items():
|
||||
if cname in _SKIP_KEYS:
|
||||
continue
|
||||
if not isinstance(flist, list):
|
||||
print(f"[ERROR] category `{cname}` must map to a list of field dicts; got {type(flist).__name__}.")
|
||||
sys.exit(1)
|
||||
for field in flist:
|
||||
if isinstance(field, dict) and "name" in field:
|
||||
defs.append((str(field["name"]), str(cname), field.get("required", None)))
|
||||
else:
|
||||
print(f"[ERROR] field entry under `{cname}` must be a dict with a `name` key; got {field!r}.")
|
||||
sys.exit(1)
|
||||
|
||||
if not defs:
|
||||
print("[ERROR] fields.yaml parsed zero fields. Ensure at least one category with field dicts.")
|
||||
sys.exit(1)
|
||||
|
||||
all_fields = {n for n, _, _ in defs}
|
||||
if any(r is not None for _, _, r in defs):
|
||||
required_fields = {n for n, _, r in defs if r}
|
||||
else:
|
||||
required_fields = set(all_fields)
|
||||
field_categories = {n: c for n, c, _ in defs}
|
||||
return all_fields, required_fields, field_categories
|
||||
|
||||
|
||||
def extract_json_fields(data, category_mapping=None):
|
||||
category_mapping = CATEGORY_MAPPING if category_mapping is None else category_mapping
|
||||
nested_keys = {k for keys in category_mapping.values() for k in keys}
|
||||
fields = set()
|
||||
stack = [(data, True)]
|
||||
while stack:
|
||||
obj, is_category_level = stack.pop()
|
||||
if isinstance(obj, dict):
|
||||
for k, v in obj.items():
|
||||
if k in _SKIP_KEYS:
|
||||
continue
|
||||
if is_category_level and k in nested_keys:
|
||||
if isinstance(v, dict):
|
||||
stack.append((v, True))
|
||||
continue
|
||||
fields.add(k)
|
||||
elif isinstance(obj, list):
|
||||
stack.extend((item, is_category_level) for item in obj if isinstance(item, dict))
|
||||
return fields
|
||||
|
||||
|
||||
def validate_json(json_path, all_fields, required_fields, field_categories):
|
||||
with json_path.open(encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
json_fields = extract_json_fields(data)
|
||||
covered = all_fields & json_fields
|
||||
missing = all_fields - json_fields
|
||||
extra = json_fields - all_fields
|
||||
missing_required = missing & required_fields
|
||||
missing_by_category = defaultdict(list)
|
||||
for field in missing:
|
||||
missing_by_category[field_categories.get(field, "Unknown")].append(field)
|
||||
return {
|
||||
"file": json_path.name,
|
||||
"total_defined": len(all_fields),
|
||||
"covered": len(covered),
|
||||
"missing": len(missing),
|
||||
"extra": len(extra),
|
||||
"coverage_rate": len(covered) / len(all_fields) * 100 if all_fields else 100,
|
||||
"missing_required": sorted(missing_required),
|
||||
"missing_optional": sorted(missing - required_fields),
|
||||
"missing_by_category": {k: sorted(v) for k, v in missing_by_category.items()},
|
||||
"extra_fields": sorted(extra),
|
||||
"valid": len(missing_required) == 0,
|
||||
}
|
||||
|
||||
|
||||
def print_result(result, verbose=True):
|
||||
status = "PASS" if result["valid"] else "FAIL"
|
||||
line = "=" * 60
|
||||
print(f"\n{line}")
|
||||
print(f"[{status}] {result['file']}")
|
||||
print(line)
|
||||
print(f"Coverage: {result['coverage_rate']:.1f}% ({result['covered']}/{result['total_defined']})")
|
||||
if result["missing_required"]:
|
||||
print(f"\n[ERROR] Missing required fields ({len(result['missing_required'])}):")
|
||||
print("\n".join(f" - {f}" for f in result["missing_required"]))
|
||||
if verbose and result["missing_optional"]:
|
||||
missing_required = set(result["missing_required"])
|
||||
print(f"\n[WARN] Missing optional fields ({len(result['missing_optional'])}):")
|
||||
for cat in sorted(result["missing_by_category"]):
|
||||
optional = [f for f in result["missing_by_category"][cat] if f not in missing_required]
|
||||
if optional:
|
||||
print(f" [{cat}]: {', '.join(optional)}")
|
||||
if verbose and result["extra_fields"]:
|
||||
extra = result["extra_fields"]
|
||||
print(f"\n[INFO] Extra fields ({len(extra)}):")
|
||||
print(f" {', '.join(extra[:10])}")
|
||||
if len(extra) > 10:
|
||||
print(f" ... and {len(extra) - 10} more")
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser(description="Validate whether JSON files cover all fields defined in fields.yaml")
|
||||
parser.add_argument("--fields", "-f", type=str, help="Path to fields.yaml", default="fields.yaml")
|
||||
parser.add_argument("--json", "-j", type=str, nargs="*", help="JSON file paths to validate")
|
||||
parser.add_argument("--dir", "-d", type=str, help="Directory containing JSON files", default="results")
|
||||
parser.add_argument("--quiet", "-q", action="store_true", help="Show summary only")
|
||||
args = parser.parse_args()
|
||||
fields_path = Path(args.fields)
|
||||
if not fields_path.exists():
|
||||
for p in (Path.cwd() / "fields.yaml", Path.cwd().parent / "fields.yaml"):
|
||||
if p.exists():
|
||||
fields_path = p
|
||||
break
|
||||
if not fields_path.exists():
|
||||
print(f"[ERROR] fields.yaml not found: {fields_path}")
|
||||
sys.exit(1)
|
||||
print(f"Field definition file: {fields_path}")
|
||||
all_fields, required_fields, field_categories = load_fields_yaml(fields_path)
|
||||
print(f"Total fields: {len(all_fields)} (required: {len(required_fields)}, optional: {len(all_fields) - len(required_fields)})")
|
||||
json_files = (
|
||||
[Path(p) for p in args.json]
|
||||
if args.json
|
||||
else sorted(Path(args.dir).glob("*.json")) if Path(args.dir).exists() else []
|
||||
)
|
||||
if not json_files:
|
||||
print("[WARN] No JSON files found")
|
||||
sys.exit(0)
|
||||
results = []
|
||||
for json_path in json_files:
|
||||
if not json_path.exists():
|
||||
print(f"[WARN] File not found: {json_path}")
|
||||
continue
|
||||
result = validate_json(json_path, all_fields, required_fields, field_categories)
|
||||
results.append(result)
|
||||
print_result(result, verbose=not args.quiet)
|
||||
line = "=" * 60
|
||||
print(f"\n{line}")
|
||||
print("Summary")
|
||||
print(line)
|
||||
passed = sum(1 for r in results if r["valid"])
|
||||
avg_coverage = sum(r["coverage_rate"] for r in results) / len(results) if results else 0
|
||||
print(f"Validation passed: {passed}/{len(results)}")
|
||||
print(f"Average coverage: {avg_coverage:.1f}%")
|
||||
if passed < len(results):
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
name: research-add-fields
|
||||
user-invocable: true
|
||||
description: 向现有调研outline补充字段定义。
|
||||
allowed-tools: Bash, Read, Write, Glob, WebSearch, Task, AskUserQuestion
|
||||
---
|
||||
|
||||
# Research Add Fields - 补充调研字段
|
||||
|
||||
## 触发方式
|
||||
`/research-add-fields`
|
||||
|
||||
## 执行流程
|
||||
|
||||
### Step 1: 自动定位Fields文件
|
||||
在当前工作目录查找 `*/fields.yaml` 文件,自动读取现有fields定义。
|
||||
|
||||
### Step 2: 获取补充来源
|
||||
询问用户选择:
|
||||
- **A. 用户直接输入**:用户提供字段名称和描述
|
||||
- **B. Web Search搜索**:启动web-search-agent搜索该领域常用字段
|
||||
|
||||
### Step 3: 展示并确认
|
||||
- 展示建议的新字段列表
|
||||
- 用户确认哪些字段需要添加
|
||||
- 用户指定字段分类和detail_level
|
||||
|
||||
### Step 4: 保存更新
|
||||
将确认的字段追加到fields.yaml,保存文件。
|
||||
|
||||
## 输出
|
||||
更新后的 `{topic}/fields.yaml` 文件(原地修改,需用户确认)
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
name: research-add-items
|
||||
user-invocable: true
|
||||
description: 向现有调研outline补充items(调研对象)。
|
||||
allowed-tools: Bash, Read, Write, Glob, WebSearch, Task, AskUserQuestion
|
||||
---
|
||||
|
||||
# Research Add Items - 补充调研对象
|
||||
|
||||
## 触发方式
|
||||
`/research-add-items`
|
||||
|
||||
## 执行流程
|
||||
|
||||
### Step 1: 自动定位Outline
|
||||
在当前工作目录查找 `*/outline.yaml` 文件,自动读取。
|
||||
|
||||
### Step 2: 并行获取补充来源
|
||||
同时进行:
|
||||
- **A. 询问用户**:需要补充哪些items?有具体名称吗?
|
||||
- **B. 询问是否需要Web Search**:是否启动agent搜索更多items?
|
||||
|
||||
### Step 3: 合并更新
|
||||
- 将新items追加到outline.yaml
|
||||
- 展示给用户确认
|
||||
- 避免重复
|
||||
- 保存更新后的outline
|
||||
|
||||
## 输出
|
||||
更新后的 `{topic}/outline.yaml` 文件(原地修改)
|
||||
@@ -0,0 +1,100 @@
|
||||
---
|
||||
name: research-deep
|
||||
user-invocable: true
|
||||
description: 读取调研outline,为每个item启动独立agent进行深度调研。禁用task output。
|
||||
allowed-tools: Bash, Read, Write, Glob, WebSearch, Task
|
||||
---
|
||||
|
||||
# Research Deep - 深度调研
|
||||
|
||||
## 触发方式
|
||||
`/research-deep`
|
||||
|
||||
## 执行流程
|
||||
|
||||
### Step 1: 自动定位Outline
|
||||
在当前工作目录查找 `*/outline.yaml` 文件,读取items列表、execution配置(含items_per_agent)。
|
||||
|
||||
### Step 2: 断点续传检查
|
||||
- 检查output_dir下已完成的JSON文件
|
||||
- 跳过已完成的items
|
||||
|
||||
### Step 3: 分批执行
|
||||
- 按batch_size分批(完成一批需要得到用户同意才可进行下一批)
|
||||
- 每个agent负责items_per_agent个项目
|
||||
- 启动web-search-agent(后台并行,禁用task output)
|
||||
|
||||
**参数获取**:
|
||||
- `{topic}`: outline.yaml中的topic字段
|
||||
- `{item_name}`: item的name字段
|
||||
- `{item_related_info}`: item的完整yaml内容(name + category + description等)
|
||||
- `{output_dir}`: outline.yaml中execution.output_dir(默认./results)
|
||||
- `{fields_path}`: {topic}/fields.yaml的绝对路径
|
||||
- `{output_path}`: {output_dir}/{item_name_slug}.json的绝对路径(slugify处理item_name:空格替换为_,移除特殊字符)
|
||||
|
||||
**硬约束**:以下prompt必须严格复述,仅替换{xxx}中的变量,禁止改写结构或措辞。
|
||||
|
||||
**Prompt模板**:
|
||||
```python
|
||||
prompt = f"""## 任务
|
||||
调研 {item_related_info},输出结构化JSON到 {output_path}
|
||||
|
||||
## 字段定义
|
||||
读取 {fields_path} 获取所有字段定义
|
||||
|
||||
## 输出要求
|
||||
1. 按fields.yaml定义的字段输出JSON
|
||||
2. 不确定的字段值标注[不确定]
|
||||
3. JSON末尾添加uncertain数组,列出所有不确定的字段名
|
||||
4. 所有字段值必须使用中文输出(调研过程可用英文,但最终JSON值为中文)
|
||||
|
||||
## 输出路径
|
||||
{output_path}
|
||||
|
||||
## 验证
|
||||
完成JSON输出后,运行验证脚本确保字段完整覆盖:
|
||||
python ~/.claude/skills/research/validate_json.py -f {fields_path} -j {output_path}
|
||||
验证通过后才算完成任务。
|
||||
"""
|
||||
```
|
||||
|
||||
**One-shot示例**(假设调研GitHub Copilot):
|
||||
```
|
||||
## 任务
|
||||
调研 name: GitHub Copilot
|
||||
category: 国际产品
|
||||
description: Microsoft/GitHub开发,首个主流AI编程助手,市场份额约40%,输出结构化JSON到 {project_dir}/results/GitHub_Copilot.json
|
||||
|
||||
## 字段定义
|
||||
读取 {project_dir}/fields.yaml 获取所有字段定义
|
||||
|
||||
## 输出要求
|
||||
1. 按fields.yaml定义的字段输出JSON
|
||||
2. 不确定的字段值标注[不确定]
|
||||
3. JSON末尾添加uncertain数组,列出所有不确定的字段名
|
||||
4. 所有字段值必须使用中文输出(调研过程可用英文,但最终JSON值为中文)
|
||||
|
||||
## 输出路径
|
||||
{project_dir}/results/GitHub_Copilot.json
|
||||
|
||||
## 验证
|
||||
完成JSON输出后,运行验证脚本确保字段完整覆盖:
|
||||
python ~/.claude/skills/research/validate_json.py -f {project_dir}/fields.yaml -j {project_dir}/results/GitHub_Copilot.json
|
||||
验证通过后才算完成任务。
|
||||
```
|
||||
|
||||
### Step 4: 等待与监控
|
||||
- 等待当前批次完成
|
||||
- 启动下一批
|
||||
- 显示进度
|
||||
|
||||
### Step 5: 汇总报告
|
||||
全部完成后输出:
|
||||
- 完成数量
|
||||
- 失败/不确定标记的items
|
||||
- 输出目录
|
||||
|
||||
## Agent配置
|
||||
- 后台执行: 是
|
||||
- Task Output: 禁用(agent完成时有明确输出文件)
|
||||
- 断点续传: 是
|
||||
@@ -0,0 +1,93 @@
|
||||
---
|
||||
name: research-report
|
||||
user-invocable: true
|
||||
description: 将deep调研结果汇总为markdown报告,覆盖所有字段,跳过不确定值。
|
||||
allowed-tools: Read, Write, Glob, Bash, AskUserQuestion
|
||||
---
|
||||
|
||||
# Research Report - 汇总报告
|
||||
|
||||
## 触发方式
|
||||
`/research-report`
|
||||
|
||||
## 执行流程
|
||||
|
||||
### Step 1: 定位结果目录
|
||||
在当前工作目录查找 `*/outline.yaml`,读取topic和output_dir配置。
|
||||
|
||||
### Step 2: 扫描可选摘要字段
|
||||
读取所有JSON结果,提取适合在目录中显示的字段(数值型、简短指标),例如:
|
||||
- github_stars
|
||||
- google_scholar_cites
|
||||
- swe_bench_score
|
||||
- user_scale
|
||||
- valuation
|
||||
- release_date
|
||||
|
||||
使用AskUserQuestion询问用户:
|
||||
- 目录中除了item名称外,还需要显示哪些字段?
|
||||
- 提供动态选项列表(基于实际JSON中存在的字段)
|
||||
|
||||
### Step 3: 生成Python转换脚本
|
||||
在 `{topic}/` 目录下生成 `generate_report.py`,脚本要求:
|
||||
- 读取output_dir下所有JSON
|
||||
- 读取fields.yaml获取字段结构
|
||||
- 覆盖每个JSON的所有字段值
|
||||
- 跳过值包含[不确定]的字段
|
||||
- 跳过uncertain数组中列出的字段
|
||||
- 生成markdown报告格式:目录(带锚点跳转+用户选择的摘要字段)+ 详细内容(按字段分类)
|
||||
- 保存到 `{topic}/report.md`
|
||||
|
||||
**目录格式要求**:
|
||||
- 必须包含每一个item
|
||||
- 每个item显示:序号、名称(锚点链接)、用户选择的摘要字段
|
||||
- 示例:`1. [GitHub Copilot](#github-copilot) - Stars: 10k | Score: 85%`
|
||||
|
||||
#### 脚本技术要点(必须遵循)
|
||||
|
||||
**1. JSON结构兼容**
|
||||
支持两种JSON结构:
|
||||
- 扁平结构:字段直接在顶层 `{"name": "xxx", "release_date": "xxx"}`
|
||||
- 嵌套结构:字段在category子dict中 `{"basic_info": {"name": "xxx"}, "technical_features": {...}}`
|
||||
|
||||
字段查找顺序:顶层 -> category映射key -> 遍历所有嵌套dict
|
||||
|
||||
**2. Category多语言映射**
|
||||
fields.yaml的category名与JSON的key可能是任意组合(中中、中英、英中、英英)。必须建立双向映射:
|
||||
```python
|
||||
CATEGORY_MAPPING = {
|
||||
"基本信息": ["basic_info", "基本信息"],
|
||||
"技术特性": ["technical_features", "technical_characteristics", "技术特性"],
|
||||
"性能指标": ["performance_metrics", "performance", "性能指标"],
|
||||
"里程碑意义": ["milestone_significance", "milestones", "里程碑意义"],
|
||||
"商业信息": ["business_info", "commercial_info", "商业信息"],
|
||||
"竞争与生态": ["competition_ecosystem", "competition", "竞争与生态"],
|
||||
"历史沿革": ["history", "历史沿革"],
|
||||
"市场定位": ["market_positioning", "market", "市场定位"],
|
||||
}
|
||||
```
|
||||
|
||||
**3. 复杂值格式化**
|
||||
- list of dicts(如key_events, funding_history):每个dict格式化为一行,用` | `分隔kv
|
||||
- 普通list:短列表用逗号连接,长列表换行显示
|
||||
- 嵌套dict:递归格式化,用分号或换行显示
|
||||
- 长文本字符串(超过100字符):添加换行符`<br>`或使用blockquote格式,提高可读性
|
||||
|
||||
**4. 额外字段收集**
|
||||
收集JSON中有但fields.yaml中没定义的字段,放入"其他信息"分类。注意过滤:
|
||||
- 内部字段:`_source_file`, `uncertain`
|
||||
- 嵌套结构顶级key:`basic_info`, `technical_features`等
|
||||
- `uncertain`数组:需要逐行显示每个字段名,不要压缩成一行
|
||||
|
||||
**5. 不确定值跳过**
|
||||
跳过条件:
|
||||
- 字段值包含`[不确定]`字符串
|
||||
- 字段名在`uncertain`数组中
|
||||
- 字段值为None或空字符串
|
||||
|
||||
### Step 4: 执行脚本
|
||||
运行 `python {topic}/generate_report.py`
|
||||
|
||||
## 输出
|
||||
- `{topic}/generate_report.py` - 转换脚本
|
||||
- `{topic}/report.md` - 汇总报告
|
||||
@@ -0,0 +1,145 @@
|
||||
---
|
||||
name: research
|
||||
user-invocable: true
|
||||
allowed-tools: Read, Write, Glob, WebSearch, Task, AskUserQuestion
|
||||
description: 对目标话题进行初步调研,生成调研outline。用于学术调研、benchmark调研、技术选型等场景。
|
||||
---
|
||||
|
||||
# Research Skill - 初步调研
|
||||
|
||||
## 触发方式
|
||||
`/research <topic>`
|
||||
|
||||
## 执行流程
|
||||
|
||||
### Step 1: 模型内部知识生成初步框架
|
||||
基于topic,利用模型已有知识生成:
|
||||
- 该领域的主要研究对象/items列表
|
||||
- 建议的调研字段框架
|
||||
|
||||
输出{step1_output},使用AskUserQuestion确认:
|
||||
- items列表是否需要增减?
|
||||
- 字段框架是否满足需求?
|
||||
|
||||
### Step 2: Web Search补充
|
||||
使用AskUserQuestion询问时间范围(如:最近6个月、2024年至今、不限)。
|
||||
|
||||
**参数获取**:
|
||||
- `{topic}`: 用户输入的调研话题
|
||||
- `{YYYY-MM-DD}`: 当前日期
|
||||
- `{step1_output}`: Step 1生成的完整输出内容
|
||||
- `{time_range}`: 用户指定的时间范围
|
||||
|
||||
**硬约束**:以下prompt必须严格复述,仅替换{xxx}中的变量,禁止改写结构或措辞。
|
||||
|
||||
启动1个web-search-agent(后台),**Prompt模板**:
|
||||
```python
|
||||
prompt = f"""## 任务
|
||||
调研话题: {topic}
|
||||
当前日期: {YYYY-MM-DD}
|
||||
|
||||
基于以下初步框架,补充最新items和推荐调研字段。
|
||||
|
||||
## 已有框架
|
||||
{step1_output}
|
||||
|
||||
## 目标
|
||||
1. 验证已有items是否遗漏重要对象
|
||||
2. 根据遗漏对象进行补充items
|
||||
3. 继续搜索{topic}相关且{time_range}内的items并补充
|
||||
4. 补充新fields
|
||||
|
||||
## 输出要求
|
||||
直接返回结构化结果(不写文件):
|
||||
|
||||
### 补充Items
|
||||
- item_name: 简要说明(为什么应该加入)
|
||||
...
|
||||
|
||||
### 推荐补充字段
|
||||
- field_name: 字段描述(为什么需要这个维度)
|
||||
...
|
||||
|
||||
### 信息来源
|
||||
- [来源1](url1)
|
||||
- [来源2](url2)
|
||||
"""
|
||||
```
|
||||
|
||||
**One-shot示例**(假设调研AI Coding发展史):
|
||||
```
|
||||
## 任务
|
||||
调研话题: AI Coding 发展史
|
||||
当前日期: 2025-12-30
|
||||
|
||||
基于以下初步框架,补充最新items和推荐调研字段。
|
||||
|
||||
## 已有框架
|
||||
### Items列表
|
||||
1. GitHub Copilot: Microsoft/GitHub开发,首个主流AI编程助手
|
||||
2. Cursor: AI-first IDE,基于VSCode
|
||||
...
|
||||
|
||||
### 字段框架
|
||||
- 基本信息: name, release_date, company
|
||||
- 技术特性: underlying_model, context_window
|
||||
...
|
||||
|
||||
## 目标
|
||||
1. 验证已有items是否遗漏重要对象
|
||||
2. 根据遗漏对象进行补充items
|
||||
3. 继续搜索AI Coding 发展史相关且2024年至今内的items并补充
|
||||
4. 补充新fields
|
||||
|
||||
## 输出要求
|
||||
直接返回结构化结果(不写文件):
|
||||
|
||||
### 补充Items
|
||||
- item_name: 简要说明(为什么应该加入)
|
||||
...
|
||||
|
||||
### 推荐补充字段
|
||||
- field_name: 字段描述(为什么需要这个维度)
|
||||
...
|
||||
|
||||
### 信息来源
|
||||
- [来源1](url1)
|
||||
- [来源2](url2)
|
||||
```
|
||||
|
||||
### Step 3: 询问用户已有字段
|
||||
使用AskUserQuestion询问用户是否有已定义的字段文件,如有则读取并合并。
|
||||
|
||||
### Step 4: 生成Outline(分离文件)
|
||||
合并{step1_output}、{step2_output}和用户已有字段,生成两个文件:
|
||||
|
||||
**outline.yaml**(items + 配置):
|
||||
- topic: 调研主题
|
||||
- items: 调研对象列表
|
||||
- execution:
|
||||
- batch_size: 并行agent数量(需AskUserQuestion确认)
|
||||
- items_per_agent: 每个agent调研项目数(需AskUserQuestion确认)
|
||||
- output_dir: 结果输出目录(默认./results)
|
||||
|
||||
**fields.yaml**(字段定义):
|
||||
- 字段分类和定义
|
||||
- 每个字段的name、description、detail_level
|
||||
- detail_level分层:极简 → 简要 → 详细
|
||||
- uncertain: 不确定字段列表(保留字段,deep阶段自动填充)
|
||||
|
||||
### Step 5: 输出并确认
|
||||
- 创建目录: `./{topic_slug}/`
|
||||
- 保存: `outline.yaml` 和 `fields.yaml`
|
||||
- 展示给用户确认
|
||||
|
||||
## 输出路径
|
||||
```
|
||||
{当前工作目录}/{topic_slug}/
|
||||
├── outline.yaml # items列表 + execution配置
|
||||
└── fields.yaml # 字段定义
|
||||
```
|
||||
|
||||
## 后续命令
|
||||
- `/research-add-items` - 补充items
|
||||
- `/research-add-fields` - 补充字段
|
||||
- `/research-deep` - 开始深度调研
|
||||
@@ -0,0 +1,197 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import json
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
CATEGORY_MAPPING = {
|
||||
"基本信息": ["basic_info", "基本信息"],
|
||||
"技术特性": ["technical_features", "technical_characteristics", "技术特性"],
|
||||
"性能指标": ["performance_metrics", "performance", "性能指标"],
|
||||
"里程碑意义": ["milestone_significance", "milestones", "里程碑意义"],
|
||||
"商业信息": ["business_info", "commercial_info", "商业信息"],
|
||||
"竞争与生态": ["competition_ecosystem", "competition", "竞争与生态"],
|
||||
"历史沿革": ["history", "历史沿革"],
|
||||
"市场定位": ["market_positioning", "market", "市场定位"],
|
||||
}
|
||||
|
||||
_SKIP_KEYS = {"_source_file", "uncertain"}
|
||||
|
||||
|
||||
def load_fields_yaml(fields_path):
|
||||
"""解析 fields.yaml,仅接受 research skill 实际生成的唯一 schema:
|
||||
|
||||
fields:
|
||||
<category>:
|
||||
- {name: ..., description: ..., detail_level: ...}
|
||||
...
|
||||
uncertain: []
|
||||
|
||||
只接受这一种格式。不符合的 fields.yaml 会直接报错退出,
|
||||
而不是以零字段静默通过。
|
||||
|
||||
Required 语义(避免校验器空转通过/说谎):
|
||||
- 若任一字段显式带 `required:` 键 -> 沿用 opt-in 语义
|
||||
- 否则(detail_level 式、无标记)-> 全部字段视为必填,因为脚本的目的就是完整覆盖。
|
||||
"""
|
||||
with fields_path.open(encoding="utf-8") as f:
|
||||
data = yaml.safe_load(f) or {}
|
||||
defs = [] # (name, category, required_or_None)
|
||||
|
||||
fn = data.get("fields")
|
||||
if not isinstance(fn, dict):
|
||||
print(f"[错误] fields.yaml 必须使用 `fields: {{<category>: [{{name, ...}}]}}` 格式;当前为 {type(fn).__name__ if fn is not None else 'None'}。")
|
||||
sys.exit(1)
|
||||
|
||||
for cname, flist in fn.items():
|
||||
if cname in _SKIP_KEYS:
|
||||
continue
|
||||
if not isinstance(flist, list):
|
||||
print(f"[错误] 分类 `{cname}` 必须映射为字段字典列表;当前为 {type(flist).__name__}。")
|
||||
sys.exit(1)
|
||||
for field in flist:
|
||||
if isinstance(field, dict) and "name" in field:
|
||||
defs.append((str(field["name"]), str(cname), field.get("required", None)))
|
||||
else:
|
||||
print(f"[错误] `{cname}` 下的字段必须是带 `name` 键的字典;当前为 {field!r}。")
|
||||
sys.exit(1)
|
||||
|
||||
if not defs:
|
||||
print("[错误] fields.yaml 解析到零个字段。请确保至少有一个分类及其字段字典。")
|
||||
sys.exit(1)
|
||||
|
||||
all_fields = {n for n, _, _ in defs}
|
||||
if any(r is not None for _, _, r in defs):
|
||||
required_fields = {n for n, _, r in defs if r}
|
||||
else:
|
||||
required_fields = set(all_fields)
|
||||
field_categories = {n: c for n, c, _ in defs}
|
||||
return all_fields, required_fields, field_categories
|
||||
|
||||
|
||||
def extract_json_fields(data, category_mapping=None):
|
||||
category_mapping = CATEGORY_MAPPING if category_mapping is None else category_mapping
|
||||
nested_keys = {k for keys in category_mapping.values() for k in keys}
|
||||
fields = set()
|
||||
stack = [(data, True)]
|
||||
while stack:
|
||||
obj, is_category_level = stack.pop()
|
||||
if isinstance(obj, dict):
|
||||
for k, v in obj.items():
|
||||
if k in _SKIP_KEYS:
|
||||
continue
|
||||
if is_category_level and k in nested_keys:
|
||||
if isinstance(v, dict):
|
||||
stack.append((v, True))
|
||||
continue
|
||||
fields.add(k)
|
||||
elif isinstance(obj, list):
|
||||
stack.extend((item, is_category_level) for item in obj if isinstance(item, dict))
|
||||
return fields
|
||||
|
||||
|
||||
def validate_json(json_path, all_fields, required_fields, field_categories):
|
||||
with json_path.open(encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
json_fields = extract_json_fields(data)
|
||||
covered = all_fields & json_fields
|
||||
missing = all_fields - json_fields
|
||||
extra = json_fields - all_fields
|
||||
missing_required = missing & required_fields
|
||||
missing_by_category = defaultdict(list)
|
||||
for field in missing:
|
||||
missing_by_category[field_categories.get(field, "未知")].append(field)
|
||||
return {
|
||||
"file": json_path.name,
|
||||
"total_defined": len(all_fields),
|
||||
"covered": len(covered),
|
||||
"missing": len(missing),
|
||||
"extra": len(extra),
|
||||
"coverage_rate": len(covered) / len(all_fields) * 100 if all_fields else 100,
|
||||
"missing_required": sorted(missing_required),
|
||||
"missing_optional": sorted(missing - required_fields),
|
||||
"missing_by_category": {k: sorted(v) for k, v in missing_by_category.items()},
|
||||
"extra_fields": sorted(extra),
|
||||
"valid": len(missing_required) == 0,
|
||||
}
|
||||
|
||||
|
||||
def print_result(result, verbose=True):
|
||||
status = "通过" if result["valid"] else "失败"
|
||||
line = "=" * 60
|
||||
print(f"\n{line}")
|
||||
print(f"[{status}] {result['file']}")
|
||||
print(line)
|
||||
print(f"覆盖率: {result['coverage_rate']:.1f}% ({result['covered']}/{result['total_defined']})")
|
||||
if result["missing_required"]:
|
||||
print(f"\n[错误] 缺少必填字段 ({len(result['missing_required'])}):")
|
||||
print("\n".join(f" - {f}" for f in result["missing_required"]))
|
||||
if verbose and result["missing_optional"]:
|
||||
missing_required = set(result["missing_required"])
|
||||
print(f"\n[警告] 缺少可选字段 ({len(result['missing_optional'])}):")
|
||||
for cat in sorted(result["missing_by_category"]):
|
||||
optional = [f for f in result["missing_by_category"][cat] if f not in missing_required]
|
||||
if optional:
|
||||
print(f" [{cat}]: {', '.join(optional)}")
|
||||
if verbose and result["extra_fields"]:
|
||||
extra = result["extra_fields"]
|
||||
print(f"\n[信息] 额外字段 ({len(extra)}):")
|
||||
print(f" {', '.join(extra[:10])}")
|
||||
if len(extra) > 10:
|
||||
print(f" ... 还有 {len(extra) - 10} 个")
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser(description="验证JSON文件是否覆盖fields.yaml中定义的所有字段")
|
||||
parser.add_argument("--fields", "-f", type=str, help="fields.yaml路径", default="fields.yaml")
|
||||
parser.add_argument("--json", "-j", type=str, nargs="*", help="要验证的JSON文件路径")
|
||||
parser.add_argument("--dir", "-d", type=str, help="包含JSON文件的目录", default="results")
|
||||
parser.add_argument("--quiet", "-q", action="store_true", help="仅显示摘要")
|
||||
args = parser.parse_args()
|
||||
fields_path = Path(args.fields)
|
||||
if not fields_path.exists():
|
||||
for p in (Path.cwd() / "fields.yaml", Path.cwd().parent / "fields.yaml"):
|
||||
if p.exists():
|
||||
fields_path = p
|
||||
break
|
||||
if not fields_path.exists():
|
||||
print(f"[错误] 找不到fields.yaml: {fields_path}")
|
||||
sys.exit(1)
|
||||
print(f"字段定义文件: {fields_path}")
|
||||
all_fields, required_fields, field_categories = load_fields_yaml(fields_path)
|
||||
print(f"总字段数: {len(all_fields)} (必填: {len(required_fields)}, 可选: {len(all_fields) - len(required_fields)})")
|
||||
json_files = (
|
||||
[Path(p) for p in args.json]
|
||||
if args.json
|
||||
else sorted(Path(args.dir).glob("*.json")) if Path(args.dir).exists() else []
|
||||
)
|
||||
if not json_files:
|
||||
print("[警告] 未找到JSON文件")
|
||||
sys.exit(0)
|
||||
results = []
|
||||
for json_path in json_files:
|
||||
if not json_path.exists():
|
||||
print(f"[警告] 文件不存在: {json_path}")
|
||||
continue
|
||||
result = validate_json(json_path, all_fields, required_fields, field_categories)
|
||||
results.append(result)
|
||||
print_result(result, verbose=not args.quiet)
|
||||
line = "=" * 60
|
||||
print(f"\n{line}")
|
||||
print("汇总")
|
||||
print(line)
|
||||
passed = sum(1 for r in results if r["valid"])
|
||||
avg_coverage = sum(r["coverage_rate"] for r in results) / len(results) if results else 0
|
||||
print(f"验证通过: {passed}/{len(results)}")
|
||||
print(f"平均覆盖率: {avg_coverage:.1f}%")
|
||||
if passed < len(results):
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
TMP_HOME="$(mktemp -d)"
|
||||
trap 'rm -rf "$TMP_HOME"' EXIT
|
||||
|
||||
assert_contains() {
|
||||
local path="$1"
|
||||
local expected="$2"
|
||||
if ! rg -F "$expected" "$path" >/dev/null 2>&1; then
|
||||
echo "expected '$expected' in $path" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
HOME="$TMP_HOME" bash "$ROOT_DIR/scripts/install-codex.sh"
|
||||
HOME="$TMP_HOME" bash "$ROOT_DIR/scripts/install-codex.sh"
|
||||
|
||||
if [[ ! -f "$TMP_HOME/.codex/config.toml" ]]; then
|
||||
echo "expected config.toml to exist" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -d "$TMP_HOME/.codex/skills" ]]; then
|
||||
echo "did not expect skills directory to be created" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -d "$TMP_HOME/.codex/agents" ]]; then
|
||||
echo "did not expect agents directory to be created" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
assert_contains "$TMP_HOME/.codex/config.toml" "multi_agent = true"
|
||||
assert_contains "$TMP_HOME/.codex/config.toml" "default_mode_request_user_input = true"
|
||||
assert_contains "$TMP_HOME/.codex/config.toml" "suppress_unstable_features_warning = true"
|
||||
assert_contains "$TMP_HOME/.codex/config.toml" "[agents.web_researcher]"
|
||||
assert_contains "$TMP_HOME/.codex/config.toml" 'config_file = "agents/web-researcher.toml"'
|
||||
|
||||
if [[ "$(rg -c '^\[features\]$' "$TMP_HOME/.codex/config.toml")" != "1" ]]; then
|
||||
echo "expected exactly one [features] section" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$(rg -c '^\[agents\.web_researcher\]$' "$TMP_HOME/.codex/config.toml")" != "1" ]]; then
|
||||
echo "expected exactly one [agents.web_researcher] section" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if awk '
|
||||
/^\[features\]$/ { in_features=1; next }
|
||||
/^\[/ { in_features=0 }
|
||||
in_features && /suppress_unstable_features_warning/
|
||||
' "$TMP_HOME/.codex/config.toml" | grep -q .; then
|
||||
echo "did not expect suppress_unstable_features_warning inside [features]" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "install-codex test passed"
|
||||
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Regression test for skills/*/research/validate_json.py.
|
||||
|
||||
The validator accepts EXACTLY ONE schema — the one /research actually emits:
|
||||
|
||||
fields:
|
||||
<category>:
|
||||
- {name: ..., description: ..., detail_level: ...}
|
||||
uncertain: []
|
||||
|
||||
Any other shape must be rejected (exit 1), never silently pass with zero fields.
|
||||
With no explicit `required:` markers, every field is required so incomplete coverage
|
||||
actually fails. With explicit markers, opt-in semantics are preserved.
|
||||
|
||||
Run: python tests/test_validate_json_schemas.py (exit 0 = all pass)
|
||||
"""
|
||||
import importlib.util
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
COPIES = sorted(ROOT.glob("skills/*/research/validate_json.py"))
|
||||
|
||||
tmp = Path(tempfile.mkdtemp())
|
||||
# The one accepted schema: fields:{<category>:[{name, detail_level}]} with NO `required` markers.
|
||||
(tmp / "good_schema.yaml").write_text(
|
||||
"fields:\n"
|
||||
" basic:\n"
|
||||
" - {name: a, detail_level: detailed}\n"
|
||||
" - {name: b, detail_level: brief}\n"
|
||||
" - {name: c, detail_level: moderate}\n"
|
||||
" - {name: d, detail_level: moderate}\n"
|
||||
"uncertain: []\n", encoding="utf-8")
|
||||
# Same shape but with explicit required markers -> opt-in semantics.
|
||||
(tmp / "marked_schema.yaml").write_text(
|
||||
"fields:\n"
|
||||
" basic:\n"
|
||||
" - {name: a, required: true}\n"
|
||||
" - {name: b, required: true}\n"
|
||||
" - {name: notes, required: false}\n", encoding="utf-8")
|
||||
# A rejected shape: the old `field_categories:` form.
|
||||
(tmp / "bad_schema.yaml").write_text(
|
||||
"field_categories:\n"
|
||||
" - category: basic\n"
|
||||
" fields:\n"
|
||||
" - {name: a}\n", encoding="utf-8")
|
||||
(tmp / "good.json").write_text(json.dumps({"a": 1, "b": 1, "c": 1, "d": 1}), encoding="utf-8")
|
||||
(tmp / "bad.json").write_text(json.dumps({"a": 1, "b": 1, "c": 1}), encoding="utf-8") # missing 'd'
|
||||
|
||||
|
||||
def load(path, i):
|
||||
spec = importlib.util.spec_from_file_location(f"vj{i}", path)
|
||||
mod = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(mod)
|
||||
return mod
|
||||
|
||||
|
||||
fails = []
|
||||
def check(label, cond):
|
||||
print(("PASS " if cond else "FAIL ") + label)
|
||||
if not cond:
|
||||
fails.append(label)
|
||||
|
||||
|
||||
assert COPIES, "no validate_json.py copies found under skills/*/research/"
|
||||
for i, path in enumerate(COPIES):
|
||||
tag = path.relative_to(ROOT).parts[1] # e.g. research-en
|
||||
m = load(path, i)
|
||||
|
||||
# 1. The one accepted schema parses all 4 fields; all required (no markers).
|
||||
a, r, _ = m.load_fields_yaml(tmp / "good_schema.yaml")
|
||||
check(f"[{tag}] good_schema parses 4 fields (was 0 before fix)", a == {"a", "b", "c", "d"})
|
||||
check(f"[{tag}] all required when unmarked (no vacuous pass)", r == a)
|
||||
|
||||
# 2. Explicit markers preserve opt-in semantics.
|
||||
am, rm, _ = m.load_fields_yaml(tmp / "marked_schema.yaml")
|
||||
check(f"[{tag}] marked_schema: 3 fields, 'notes' optional", am == {"a", "b", "notes"} and rm == {"a", "b"})
|
||||
|
||||
# 3. A complete JSON passes; a JSON missing a field actually fails.
|
||||
good = m.validate_json(tmp / "good.json", a, r, _)
|
||||
bad = m.validate_json(tmp / "bad.json", a, r, _)
|
||||
check(f"[{tag}] good.json -> valid", good["valid"])
|
||||
check(f"[{tag}] bad.json -> INVALID (catches missing 'd')", (not bad["valid"]) and "d" in bad["missing_required"])
|
||||
|
||||
# 4. A rejected schema shape must make the CLI exit non-zero (run as subprocess).
|
||||
proc = subprocess.run([sys.executable, str(path), "-f", str(tmp / "bad_schema.yaml"), "-d", str(tmp)],
|
||||
capture_output=True, text=True)
|
||||
check(f"[{tag}] bad_schema (field_categories) is REJECTED (exit != 0)", proc.returncode != 0)
|
||||
|
||||
print("\nRESULT:", "ALL PASS" if not fails else f"{len(fails)} FAILED -> {fails}")
|
||||
sys.exit(1 if fails else 0)
|
||||
BIN
research-what-we-did/Deep-Research-skills/workflow.png
Normal file
BIN
research-what-we-did/Deep-Research-skills/workflow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 452 KiB |
Reference in New Issue
Block a user