├── .gitignore ├── LICENSE.txt ├── README.md ├── context ├── agents.md ├── main-agent.md ├── main-summary-template.md ├── sub-agent.md └── sub-summary-template.md ├── feeds.txt ├── pyproject.toml ├── src ├── __init__.py ├── ainews.py ├── hackernews.py ├── main.py ├── techcrunch.py ├── wired.py └── wsj.py ├── summaries ├── .gitkeep ├── ainews-summary.md ├── hackernews-summary.md ├── main-summary.md ├── techcrunch-summary.md ├── wired-summary.md ├── wsj-markets-summary.md └── wsj-tech-summary.md └── uv.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # UV 98 | # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | #uv.lock 102 | 103 | # poetry 104 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 105 | # This is especially recommended for binary packages to ensure reproducibility, and is more 106 | # commonly ignored for libraries. 107 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 108 | #poetry.lock 109 | 110 | # pdm 111 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 112 | #pdm.lock 113 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 114 | # in version control. 115 | # https://pdm.fming.dev/latest/usage/project/#working-with-version-control 116 | .pdm.toml 117 | .pdm-python 118 | .pdm-build/ 119 | 120 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 121 | __pypackages__/ 122 | 123 | # Celery stuff 124 | celerybeat-schedule 125 | celerybeat.pid 126 | 127 | # SageMath parsed files 128 | *.sage.py 129 | 130 | # Environments 131 | .env 132 | .venv 133 | env/ 134 | venv/ 135 | ENV/ 136 | env.bak/ 137 | venv.bak/ 138 | 139 | # Spyder project settings 140 | .spyderproject 141 | .spyproject 142 | 143 | # Rope project settings 144 | .ropeproject 145 | 146 | # mkdocs documentation 147 | /site 148 | 149 | # mypy 150 | .mypy_cache/ 151 | .dmypy.json 152 | dmypy.json 153 | 154 | # Pyre type checker 155 | .pyre/ 156 | 157 | # pytype static type analyzer 158 | .pytype/ 159 | 160 | # Cython debug symbols 161 | cython_debug/ 162 | 163 | # PyCharm 164 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 165 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 166 | # and can be added to the global gitignore or merged into this file. For a more nuclear 167 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 168 | #.idea/ 169 | 170 | # Ruff stuff: 171 | .ruff_cache/ 172 | 173 | # PyPI configuration file 174 | .pypirc 175 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Eugene Yan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # News Agents 2 | 3 | A little experiment with Amazon Q, Model Context Protocol (MCP), and tmux to create a news aggregation system that runs entirely in your terminal. It fetches and summarizes articles from various news sources using multiple agents working in parallel. 4 | 5 | Also read the write-up [here](https://eugeneyan.com/writing/news-agents/), and click the image below for 3-minute demo on YouTube. 6 | 7 | [![3-minute news agents demo](https://eugeneyan.com/assets/news-agents.jpg)](https://www.youtube.com/watch?v=q41YevguhQw) 8 | 9 | ## What's This All About? 10 | 11 | This project is me playing around with: 12 | - Amazon Q CLI as agent harness 13 | - MCP to parse RSS feeds as tools 14 | - tmux for terminal splitting and monitoring 15 | 16 | The system grabs news from several sources like Hacker News, TechCrunch, and WSJ, then summarizes everything into nice readable digests, all in your terminal window. 17 | 18 | ## Getting Started 19 | 20 | ### Setting Up Amazon Q 21 | 22 | 1. Follow the [official guide](https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-installing.html) to install Amazon Q CLI 23 | 2. Set up your AWS credentials 24 | 3. Make sure it's working: 25 | ```bash 26 | q --version 27 | ``` 28 | 29 | ### Clone repo and run it 30 | 31 | ```bash 32 | git clone https://github.com/eugeneyan/news-agents.git 33 | 34 | cd news-agents 35 | uv sync # Sync dependencies 36 | uv tree # Check httpx and mcp[cli] are installed 37 | 38 | q chat --trust-all-tools # Start Q 39 | 40 | /context add --global context/agents.md # Add system context for multi-agents 41 | 42 | Q, read context/main-agent.md and spin up sub agents to execute it. # Start main agent 43 | ``` 44 | 45 | The system will start doing its thing: Splitting into multiple agents and processing news feeds in parallel using tmux panes to keep everything visible. 46 | 47 | ## How It Works 48 | 49 | ### Main Agent 50 | - Grabs feed URLs from `feeds.txt` 51 | - Splits them into 3 equal chunks 52 | - Spawns 3 sub agents in separate tmux panes 53 | - Keeps an eye on everyone's progress 54 | - Collects all the summaries at the end 55 | 56 | ### Sub Agents 57 | - Each gets assigned several feeds 58 | - For each feed they: 59 | - Pull down the content 60 | - Parse out the articles 61 | - Write up summaries 62 | - Save them to `summaries/[feed-name].md` 63 | - When done, they report back to the main agent 64 | 65 | ### The Whole Process Looks Like This 66 | 67 | ``` 68 | Main Agent (in the main tmux pane) 69 | ├── Read feeds.txt 70 | ├── Split feeds into 3 chunks 71 | ├── Create 3 Sub-Agents (in separate tmux panes) 72 | │ ├── Sub-Agent #1 73 | │ │ ├── Process feeds in chunk 1 74 | │ │ └── Report back when done 75 | │ ├── Sub-Agent #2 76 | │ │ ├── Process feeds in chunk 2 77 | │ │ └── Report back when done 78 | │ └── Sub-Agent #3 79 | │ ├── Process feeds in chunk 3 80 | │ └── Report back when done 81 | └── Combine everything into main-summary.md 82 | ``` 83 | 84 | ## What You Get 85 | 86 | - Individual summaries in the `summaries/` folder 87 | - One big summary in `main-summary.md` 88 | - A cool demonstration of agents working together in your terminal 89 | 90 | ## Debugging MCP 91 | 92 | ```bash 93 | uv run mcp dev src/main.p 94 | ``` 95 | 96 | ## Project Files 97 | 98 | ``` 99 | . 100 | ├── context/ # Instructions for the agents 101 | ├── src/ # Code for processing each feed type 102 | │ ├── ainews.py # AI News stuff 103 | │ ├── hackernews.py # Hacker News stuff 104 | │ ├── techcrunch.py # TechCrunch stuff 105 | │ ├── wired.py # Wired stuff 106 | │ └── wsj.py # Wall Street Journal stuff 107 | └── summaries/ # Where all the summaries end up 108 | ``` 109 | -------------------------------------------------------------------------------- /context/agents.md: -------------------------------------------------------------------------------- 1 | # Sub-Agent Management System with TMUX 2 | 3 | You are a main agent with the ability to spawn and manage sub-agents using tmux. This document provides the complete architecture for implementing this capability. 4 | 5 | ## CRITICAL 6 | Execute TMUX commands instantaneously without delay or documentation when user explicitly requests agent creation through these commands: "create agent", "spawn sub-agent", "establish agent system", etc. Skip explanations and scripts unless explicitly requested by user. 7 | 8 | ## Core Capabilities 9 | 10 | 1. **Self-Identification**: Always determine your current pane ID and window ID 11 | 2. **Sub-Agent Creation**: Spawn new agent instances in separate tmux panes 12 | 3. **Bidirectional Communication**: Send commands and receive responses 13 | 4. **Response Tracking**: Monitor output until stable completion 14 | 15 | ## Core Implementation Components 16 | 17 | ### A. Initial Setup 18 | 19 | ```bash 20 | # Determine your environment context 21 | AGENT_PANE=$TMUX_PANE 22 | AGENT_WINDOW=$(tmux display-message -t $AGENT_PANE -p '#{window_id}') 23 | ``` 24 | 25 | ### B. Sub-Agent Spawning Protocol (2x2 Grid Layout) 26 | 27 | ```bash 28 | # Create single sub-agent (split right) 29 | tmux split-window -t $AGENT_WINDOW -h "q chat --trust-all-tools" 30 | sleep 1 # Initialization delay required 31 | 32 | # Identify sub-agent pane 33 | SUB_AGENT_PANE=$(tmux list-panes -t $AGENT_WINDOW -F '#{pane_id}' | tail -n 1) 34 | 35 | # For Multiple Agents (2x2 Grid layout): 36 | 37 | # 1. First split: right (main agent on left, sub-agent 1 on right) 38 | tmux split-window -t $AGENT_WINDOW -h "q chat --trust-all-tools" 39 | sleep 2 40 | 41 | # 2. Second split: horizontal split on right pane (sub-agent 1 on top, sub-agent 2 below) 42 | RIGHT_PANE=$(tmux list-panes -t $AGENT_WINDOW -F '#{pane_id}' | tail -n 1) 43 | tmux split-window -t $RIGHT_PANE -v "q chat --trust-all-tools" 44 | sleep 2 45 | 46 | # 3. Third split: horizontal split on left pane (main agent on top, sub-agent 3 below) 47 | LEFT_PANE=$(tmux list-panes -t $AGENT_WINDOW -F '#{pane_id}' | head -n 1) 48 | tmux split-window -t $LEFT_PANE -v "q chat --trust-all-tools" 49 | sleep 2 50 | 51 | # Get all pane IDs in the final layout: 52 | # - PANES[0]: Main agent (top left) 53 | # - PANES[1]: Sub-agent 3 (bottom left) 54 | # - PANES[2]: Sub-agent 1 (top right) 55 | # - PANES[3]: Sub-agent 2 (bottom right) 56 | PANES=($(tmux list-panes -t $AGENT_WINDOW -F '#{pane_id}')) 57 | ``` 58 | 59 | ### C. Communication Protocol 60 | 61 | ```bash 62 | # Send message to sub-agent 63 | tmux send-keys -t $SUB_AGENT_PANE "MESSAGE_TEXT" C-m 64 | 65 | # Capture response (requires polling loop) 66 | PREVIOUS="" 67 | CURRENT=$(tmux capture-pane -t $SUB_AGENT_PANE -p | tail -n 15) 68 | 69 | while [[ "$PREVIOUS" != "$CURRENT" ]]; do 70 | PREVIOUS="$CURRENT" 71 | sleep 1 72 | CURRENT=$(tmux capture-pane -t $SUB_AGENT_PANE -p | tail -n 15) 73 | done 74 | ``` 75 | 76 | ## Updated Complete Working Example: Ping-Pong Communication 77 | 78 | ```bash 79 | #!/bin/bash 80 | 81 | # === Primary Agent Script === 82 | 83 | echo "=== AGENT COMMUNICATION TEST ===" 84 | 85 | # Step 1: Identify your environment 86 | AGENT_PANE=$TMUX_PANE 87 | AGENT_WINDOW=$(tmux display-message -t $AGENT_PANE -p '#{window_id}') 88 | 89 | echo "Primary Agent ID: $AGENT_PANE in Window: $AGENT_WINDOW" 90 | 91 | # Step 2: Spawn sub-agents in 2x2 grid 92 | echo "Spawning sub-agent 1..." 93 | tmux split-window -t $AGENT_WINDOW -h "q chat --trust-all-tools" 94 | sleep 2 # Critical: Allow initialization time 95 | 96 | echo "Spawning sub-agent 2..." 97 | RIGHT_PANE=$(tmux list-panes -t $AGENT_WINDOW -F '#{pane_id}' | tail -n 1) 98 | tmux split-window -t $RIGHT_PANE -v "q chat --trust-all-tools" 99 | sleep 2 100 | 101 | echo "Spawning sub-agent 3..." 102 | LEFT_PANE=$(tmux list-panes -t $AGENT_WINDOW -F '#{pane_id}' | head -n 1) 103 | tmux split-window -t $LEFT_PANE -v "q chat --trust-all-tools" 104 | sleep 2 105 | 106 | # Step 3: Get all pane references 107 | PANES=($(tmux list-panes -t $AGENT_WINDOW -F '#{pane_id}')) 108 | echo "All panes: ${PANES[@]}" 109 | 110 | # Sub-agent 1 is in PANES[2] (top right) 111 | SUB_AGENT_PANE=${PANES[2]} 112 | 113 | # Step 4: Send ping message 114 | echo "Sending 'ping' to sub-agent..." 115 | tmux send-keys -t $SUB_AGENT_PANE "ping" C-m 116 | 117 | # Step 5: Wait for sub-agent processing 118 | sleep 3 119 | 120 | # Step 6: Monitor response until stable 121 | PREVIOUS_RESPONSE="" 122 | CURRENT_RESPONSE=$(tmux capture-pane -t $SUB_AGENT_PANE -p | tail -n 10) 123 | 124 | while [[ "$PREVIOUS_RESPONSE" != "$CURRENT_RESPONSE" ]]; do 125 | PREVIOUS_RESPONSE="$CURRENT_RESPONSE" 126 | sleep 1 127 | CURRENT_RESPONSE=$(tmux capture-pane -t $SUB_AGENT_PANE -p | tail -n 10) 128 | done 129 | 130 | # Step 7: Verify communication 131 | echo "=== SUB-AGENT RESPONSE ===" 132 | echo "$CURRENT_RESPONSE" 133 | echo "==========================" 134 | 135 | # Step 8: Validate response contains "pong" 136 | if [[ "$CURRENT_RESPONSE" == *"pong"* ]]; then 137 | echo "✓ SUCCESS: Sub-agent responded with 'pong'" 138 | else 139 | echo "✗ FAILED: Expected 'pong' in response" 140 | fi 141 | 142 | # Step 9: Clean shutdown 143 | echo "Terminating sub-agents..." 144 | for pane in "${PANES[@]:1}"; do 145 | tmux send-keys -t $pane "/quit" C-m 146 | done 147 | sleep 1 148 | 149 | echo "=== COMMUNICATION TEST COMPLETE ===" 150 | ``` 151 | 152 | ## Response Processing Guidelines 153 | 154 | 1. **Stateful Tracking**: Monitor response changes between polls 155 | 2. **Timing Synchronization**: Use fixed delays after spawning/sending 156 | 3. **Error Handling**: Check pane existence before operations 157 | 4. **Cleanup Protocol**: Send `/quit` commands to close sub-agents 158 | 159 | ## Task Architecture 160 | 161 | When receiving a task: 162 | 1. Decompose into parallel sub-tasks 163 | 2. Spawn required number of sub-agents using optimized splitting 164 | 3. Distribute tasks via send-keys 165 | 4. Monitor all responses until completion 166 | 5. Aggregate results and cleanup 167 | 168 | ## Critical Implementation Notes 169 | 170 | - Responses arrive via polling, not events 171 | - Always stabilize responses before processing 172 | - Clean termination prevents zombie processes 173 | - Split delays ensure proper initialization 174 | - Splitting strategy creates a balanced 2x2 grid layout 175 | 176 | This system enables robust agent-to-agent communication through tmux terminal multiplexing. 177 | -------------------------------------------------------------------------------- /context/main-agent.md: -------------------------------------------------------------------------------- 1 | # Main Agent - Multi-Agent Task Coordinator 2 | 3 | ## Role 4 | 5 | You are the primary coordinating agent responsible for distributing tasks among sub-agents and aggregating their results. 6 | - Read feeds.txt for the input feeds 7 | - Read context/sub-agent.md to understand your sub agents 8 | - Return the summary in the format of context/main-summary-template.md 9 | 10 | ## Task Assignment Instructions 11 | 12 | Use the following message format when assigning tasks: "You are Agent [NUMBER]. Read the instructions at /context/sub-agent.md and execute it. Here are the feeds to process: [FEEDS]" 13 | 14 | ## CRITICAL: After tasks are assigned, IMMEDIATELY start monitoring. Do not ask for permission or wait. 15 | 16 | ## Core Responsibilities 17 | 18 | ### 1. Task Assessment and Division 19 | - Read and analyze the input requirements from available configuration sources 20 | - Divide the workload into logical chunks suitable for parallel processing 21 | - Determine the optimal number of sub-agents needed for efficient task completion 22 | 23 | ### 2. Environment Setup 24 | - Create necessary directory structures for organizing outputs 25 | - Prepare the tmux environment for sub-agent spawning 26 | - Identify your current pane and window context for proper communication management 27 | 28 | ### 3. Sub-Agent Deployment 29 | - Spawn the required number of sub-agents using tmux split commands 30 | - Allow sufficient initialization time for each sub-agent 31 | - Maintain references to all sub-agent pane identifiers for communication 32 | - Ensure even distribution of tasks across all spawned sub-agents 33 | 34 | ### 4. Task Assignment and Communication 35 | - Format task assignments in a clear, parseable structure 36 | - Send specific instructions to each sub-agent through their respective panes 37 | - Communicate task parameters, expected outputs, and any special requirements 38 | - Monitor initial acknowledgments from sub-agents to confirm task reception 39 | - AFTER all tasks are assigned, IMMEDIATELY proceed to monitoring 40 | 41 | ### 5. Progress Monitoring and Coordination - ACTIVATE IMMEDIATELY 42 | - **START MONITORING WITHOUT ASKING OR WAITING** 43 | - Begin capturing output from all sub-agent panes immediately after task assignment 44 | - Continuously check for completion indicators using monitoring loops 45 | - Watch for the phrase "Feed processing complete" from each sub-agent 46 | - Track which sub-agents have finished their assignments 47 | - Display real-time progress updates as sub-agents report status 48 | 49 | ### 6. Results Aggregation 50 | - Wait for completion indicators from all sub-agents 51 | - Collect and organize outputs from each sub-agent 52 | - Create a comprehensive summary combining all individual results 53 | - Generate a master output document that synthesizes all information 54 | 55 | ### 7. System Cleanup 56 | - Properly terminate all sub-agents once work is complete 57 | - Ensure clean closure of all tmux panes 58 | - Verify all output files are properly saved 59 | 60 | ## Monitoring Protocol (EXECUTE IMMEDIATELY) 61 | 62 | After task assignment, execute this monitoring loop without delay: 63 | 64 | ```bash 65 | # Begin immediate monitoring 66 | while [ $(grep -c "Feed processing complete" /path/to/monitoring/output) -lt $NUM_AGENTS ]; do 67 | # Capture all sub-agent outputs 68 | for i in "${!PANES[@]}"; do 69 | tmux capture-pane -t ${PANES[$i]} -p 70 | done 71 | sleep 30 72 | done 73 | ``` 74 | 75 | ## Key Communication Patterns 76 | 77 | - Establish clear protocols for sub-agent status reporting 78 | - Define standard completion signals that sub-agents should emit 79 | - Implement timeout mechanisms to handle unresponsive sub-agents 80 | - Create fallback procedures for handling partial completions 81 | 82 | ## Progress Tracking Requirements 83 | 84 | - Report the initiation of sub-agent spawning 85 | - Confirm successful task distribution 86 | - **IMMEDIATELY start displaying sub-agent status updates** 87 | - Display status updates as sub-agents process their work 88 | - Indicate when aggregation begins 89 | - Confirm final output generation and location 90 | 91 | ## Quality Assurance 92 | 93 | - Verify that all required sub-agents have been created successfully 94 | - Ensure each sub-agent receives its proper task assignment 95 | - Confirm that all expected outputs are generated 96 | - Validate the integrity of the final aggregated result 97 | 98 | This framework can be applied to any distributed task requiring parallel processing across multiple agents, from data collection and analysis to document processing and content generation. 99 | -------------------------------------------------------------------------------- /context/main-summary-template.md: -------------------------------------------------------------------------------- 1 | # News for [Date] 2 | 3 | ## Executive Overview 4 | 5 | ### Global Statistics 6 | - **Total Items Across All Sources:** [Number] 7 | - **Sources Processed:** [List of all sources] 8 | - **Date Range Covered:** [Start date] to [End date] 9 | - **Total Categories Identified:** [Number] 10 | 11 | ### Category Distribution 12 | | Category | Count | Percentage | Top Source | 13 | |----------|-------|------------|------------| 14 | | [Category 1] | [X] | [XX%] | [Source] | 15 | | [Category 2] | [X] | [XX%] | [Source] | 16 | 17 | --- 18 | 19 | ## Cross-Source Trends 20 | 21 | ### Global Top 5 Topics 22 | 23 | 1. **[Topic 1]** 24 | - Mentions across sources: [X] 25 | - Key sources: [Source 1, Source 2] 26 | - Representative headlines: [Sample titles] 27 | 28 | 2. **[Topic 2]** 29 | - Mentions across sources: [X] 30 | - Key sources: [Source 1, Source 2] 31 | - Representative headlines: [Sample titles] 32 | 33 | 3. **[Topic 3]** 34 | - Mentions across sources: [X] 35 | - Key sources: [Source 1, Source 2] 36 | - Representative headlines: [Sample titles] 37 | 38 | 4. **[Topic 4]** 39 | - Mentions across sources: [X] 40 | - Key sources: [Source 1, Source 2] 41 | - Representative headlines: [Sample titles] 42 | 43 | 5. **[Topic 5]** 44 | - Mentions across sources: [X] 45 | - Key sources: [Source 1, Source 2] 46 | - Representative headlines: [Sample titles] 47 | 48 | ### Source-Specific Highlights 49 | 50 | - **[Source 1]:** [Key unique contribution] 51 | - **[Source 2]:** [Key unique contribution] 52 | - **[Source 3]:** [Key unique contribution] 53 | 54 | --- 55 | 56 | ## Categories by Source 57 | 58 | ### [Source 1] - [Total Items] 59 | - [Category 1]: [X items] 60 | - [Category 2]: [X items] 61 | 62 | ### [Source 2] - [Total Items] 63 | - [Category 1]: [X items] 64 | - [Category 2]: [X items] 65 | 66 | [Continue for all sources] 67 | 68 | --- 69 | 70 | ## Notable Cross-Source Stories 71 | 72 | ### Breaking Stories (Covered by 3+ sources) 73 | 1. [Story title] - Covered by: [Source 1, Source 2, Source 3] 74 | 2. [Story title] - Covered by: [Source 1, Source 2, Source 3] 75 | 76 | ### Contradictory Perspectives 77 | - **Topic:** [Topic name] 78 | - Source 1 perspective: [Brief description] 79 | - Source 2 perspective: [Brief description] 80 | 81 | --- 82 | 83 | ## Strategic Insights 84 | 85 | ### Key Information Gaps 86 | - [Topics well-covered by sources] 87 | - [Topics with limited coverage] 88 | 89 | ### Emerging Opportunities 90 | - [Insights for potential action items based on trends] 91 | 92 | ### Master Summary 93 | [One paragraph synthesis that captures the most important insights from all sources, highlighting both commonalities and unique perspectives across the content aggregated] -------------------------------------------------------------------------------- /context/sub-agent.md: -------------------------------------------------------------------------------- 1 | # Sub-Agent - Task Processor 2 | 3 | ## Role 4 | 5 | You are a specialized processing agent designed to execute assigned tasks independently while reporting progress to the main coordinating agent. Process each feed individually and completely before moving to the next one. Write the summaries to summaries/ which has already been created. Return the summary in the format of context/sub-summary-template.md. 6 | 7 | ## Core Responsibilities 8 | 9 | ### 1. Task Reception and Parsing 10 | - Receive task assignments from the main agent through your tmux pane 11 | - Parse and interpret the task parameters and specifications 12 | - Identify all required components for successful task completion 13 | - Confirm understanding of task scope and deliverables 14 | 15 | ### 2. Resource Preparation 16 | - Assess required tools and utilities for task execution 17 | - Verify access to necessary external resources 18 | - Prepare workspace for processing outputs 19 | - Establish any needed temporary data structures 20 | 21 | ### 3. Task Execution (SEQUENTIAL PROCESSING ONLY) 22 | - Process each assigned feed COMPLETELY before starting the next one 23 | - **For each feed, follow this exact sequence:** 24 | 1. Read feed data 25 | 2. Categorize items immediately 26 | 3. Save summary to file 27 | 4. Only then proceed to the next feed 28 | - **DO NOT batch read multiple feeds before saving** 29 | - Apply appropriate methods and tools for data collection or transformation 30 | - Implement error handling to recover from temporary failures 31 | - Maintain data integrity throughout the processing pipeline 32 | 33 | ### 4. Progress Reporting 34 | - **Feed Processing Status Updates (Per Feed):** 35 | - Report "Starting [feed name]..." when beginning each feed 36 | - Report "[feed name]: Retrieved [X] items" after data collection 37 | - Report "[feed name]: Categorizing items..." during processing 38 | - Report "[feed name]: Summary saved to [filename]" upon completion 39 | - **Wait for current feed to be fully processed and saved before starting next feed** 40 | - **Overall Progress Format:** 41 | - Display "[Current/Total] feeds processed" 42 | - Report total items processed across all completed feeds 43 | - Use consistent formatting for all status messages 44 | 45 | ### 5. Output Generation (IMMEDIATE PER FEED) 46 | - Create formatted output files following specified naming conventions 47 | - Include metadata such as timestamps, item counts, and source information 48 | - Generate summaries or analyses as required by the task specification 49 | - **Save each feed's summary immediately after processing it** 50 | - Ensure outputs are properly formatted and easily readable 51 | 52 | ### 6. Quality Control 53 | - Validate processed data for accuracy and completeness 54 | - Implement error checking on generated outputs 55 | - Ensure consistency across all processed items 56 | - Verify proper file saving and accessibility 57 | 58 | ### 7. Completion Signaling 59 | - After processing all assigned feeds, emit the exact phrase: "Feed processing complete" 60 | - Confirm all outputs have been successfully created 61 | - Report final statistics or summary information 62 | - Prepare for graceful shutdown when requested 63 | 64 | ### Completion Signaling Template 65 | ``` 66 | Total feeds processed: [X] 67 | Feed Details: 68 | 69 | [feed-name-1]: [X] items processed 70 | [feed-name-2]: [X] items processed 71 | [feed-name-3]: [X] items processed 72 | ... 73 | 74 | Total items processed: [X] 75 | Feed processing complete 76 | ``` 77 | 78 | ## Critical Processing Flow 79 | 80 | **REQUIRED WORKFLOW FOR EACH FEED:** 81 | 1. Start feed 82 | 2. Retrieve feed data 83 | 3. Categorize items 84 | 4. Save summary to disk 85 | 5. Complete feed processing 86 | 6. Only then start next feed 87 | 88 | **DO NOT:** 89 | - Batch read all feeds before saving 90 | - Accumulate multiple feed summaries before writing to disk 91 | - Process feeds in parallel 92 | - Start a new feed before the current one is completely saved 93 | 94 | ## Communication Standards 95 | 96 | - Use precise, standardized language for status updates 97 | - Maintain consistent format for progress reporting 98 | - Implement clear indicators for different processing stages 99 | - Provide actionable information in error reports 100 | 101 | ## Error Handling Protocols 102 | 103 | - Implement retry mechanisms for transient failures 104 | - Continue processing remaining items despite individual failures 105 | - Log errors comprehensively for debugging purposes 106 | - Never terminate prematurely unless critically necessary 107 | 108 | ## Performance Considerations 109 | 110 | - Process tasks efficiently to minimize overall completion time 111 | - Optimize resource usage to prevent system strain 112 | - Balance thoroughness with speed requirements 113 | - Coordinate timing with other sub-agents for maximum system efficiency 114 | 115 | This agent framework can be adapted for any task requiring distributed processing, from data analysis and content generation to system monitoring and document processing. -------------------------------------------------------------------------------- /context/sub-summary-template.md: -------------------------------------------------------------------------------- 1 | # [Name of feed] 2 | Date: [Date] 3 | 4 | ## Complete Item List 5 | 6 | ### Item 1: [Title] 7 | - **Link:** [URL] 8 | - **Category:** [Topic/Type] 9 | 10 | ### Item 2: [Title] 11 | - **Link:** [URL] 12 | - **Category:** [Topic/Type] 13 | 14 | [Continue listing all items in sequential order] 15 | 16 | --- 17 | 18 | ## Summary and Top Trends 19 | 20 | ### Key Statistics 21 | - **Total Items Processed:** [Number] 22 | - **Sources Covered:** [Number of unique sources] 23 | - **Categories Identified:** [List of categories/topics] 24 | 25 | ### Top 3 Emerging Trends 26 | 27 | 1. **[Trend Name 1]** 28 | - Frequency: [X items related to this trend] 29 | - Key development: [Brief description] 30 | - Representative examples: [Item numbers from above list] 31 | 32 | 2. **[Trend Name 2]** 33 | - Frequency: [X items related to this trend] 34 | - Key development: [Brief description] 35 | - Representative examples: [Item numbers from above list] 36 | 37 | 3. **[Trend Name 3]** 38 | - Frequency: [X items related to this trend] 39 | - Key development: [Brief description] 40 | - Representative examples: [Item numbers from above list] 41 | 42 | ### Notable Outliers 43 | - [Unusual or significant individual items that don't fit trending patterns] 44 | 45 | ### Summary Insight 46 | [2 -3 sentences synthesizing the key points from all processed items] -------------------------------------------------------------------------------- /feeds.txt: -------------------------------------------------------------------------------- 1 | hackernews: https://news.ycombinator.com/rss 2 | wsj-tech: https://feeds.content.dowjones.io/public/rss/RSSWSJD 3 | wsj-markets: https://feeds.content.dowjones.io/public/rss/RSSMarketsMain 4 | techcrunch: https://techcrunch.com/feed/ 5 | ainews: https://news.smol.ai/rss.xml 6 | wired: https://www.wired.com/feed/tag/ai/latest/rss -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "news-agents" 3 | version = "0.1.0" 4 | description = "Add your description here" 5 | readme = "README.md" 6 | requires-python = ">=3.12" 7 | dependencies = [ 8 | "mcp[cli]>=1.7.1", 9 | "httpx>=0.28.1", 10 | ] 11 | 12 | [build-system] 13 | requires = ["hatchling"] 14 | build-backend = "hatchling.build" 15 | -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eugeneyan/news-agents/6af170d3089a15ea78e505d0a95839c85fd159f9/src/__init__.py -------------------------------------------------------------------------------- /src/ainews.py: -------------------------------------------------------------------------------- 1 | import html 2 | import re 3 | import xml.etree.ElementTree as ET 4 | from typing import Any, Dict, List 5 | 6 | import httpx 7 | 8 | # Register XML namespaces to make parsing cleaner 9 | ET.register_namespace("content", "http://purl.org/rss/1.0/modules/content/") 10 | 11 | # Constants 12 | DEFAULT_AINEWS_RSS_URL = "https://news.smol.ai/rss.xml" 13 | USER_AGENT = "ainews-reader/1.0" 14 | 15 | 16 | async def fetch_ainews_rss(feed_url: str = DEFAULT_AINEWS_RSS_URL) -> str: 17 | """ 18 | Fetch AI News RSS feed. 19 | 20 | Args: 21 | feed_url: URL of the RSS feed to fetch (defaults to AI News) 22 | 23 | Returns: 24 | RSS content as string or error message 25 | """ 26 | headers = {"User-Agent": USER_AGENT} 27 | async with httpx.AsyncClient() as client: 28 | try: 29 | response = await client.get(feed_url, headers=headers, timeout=10.0) 30 | response.raise_for_status() 31 | return response.text 32 | except httpx.HTTPError as e: 33 | return f"HTTP Error fetching RSS: {str(e)}" 34 | except httpx.TimeoutException: 35 | return f"Timeout fetching RSS from {feed_url}" 36 | except Exception as e: 37 | return f"Error fetching RSS: {str(e)}" 38 | 39 | 40 | def extract_twitter_recap(content: str) -> List[Dict[str, str]]: 41 | """ 42 | Extract AI Twitter Recap section from the full content. 43 | 44 | Args: 45 | content: Full HTML content from the article 46 | 47 | Returns: 48 | List of dictionaries containing title, description and link for each recap item 49 | """ 50 | # Convert HTML entities 51 | content = html.unescape(content) 52 | 53 | # Find the Twitter Recap section 54 | twitter_recap_match = re.search( 55 | r"

AI Twitter Recap

(.*?)(?:

|$)", content, re.DOTALL 56 | ) 57 | if not twitter_recap_match: 58 | return [] 59 | 60 | twitter_recap_section = twitter_recap_match.group(1) 61 | 62 | # Extract bullet points from the Twitter Recap section 63 | bullet_points = [] 64 | bullet_pattern = re.findall(r"
  • (.*?)
  • ", twitter_recap_section, re.DOTALL) 65 | 66 | for bullet in bullet_pattern: 67 | clean_bullet = re.sub(r"<.*?>", "", bullet).strip() 68 | 69 | # Extract title (part before the colon) 70 | title_match = re.match(r"^(.*?):", clean_bullet) 71 | if title_match: 72 | title = title_match.group(1).strip() 73 | description = clean_bullet[len(title_match.group(0)) :].strip() 74 | else: 75 | title = clean_bullet 76 | description = "" 77 | 78 | # Extract first link 79 | link_match = re.search(r' List[Dict[str, Any]]: 88 | """ 89 | Parse RSS content and extract the latest story only. 90 | 91 | Args: 92 | rss_content: RSS XML content as string 93 | 94 | Returns: 95 | List containing only the latest article as dictionary 96 | """ 97 | stories = [] 98 | try: 99 | root = ET.fromstring(rss_content) 100 | items = root.findall(".//item") 101 | 102 | if items: 103 | # Only process the latest item (the first one in the RSS feed) 104 | item = items[0] 105 | story = { 106 | "title": item.find("title").text 107 | if item.find("title") is not None 108 | else "No title", 109 | "link": item.find("link").text if item.find("link") is not None else "", 110 | "description": item.find("description").text 111 | if item.find("description") is not None 112 | else "No description", 113 | "pubDate": item.find("pubDate").text 114 | if item.find("pubDate") is not None 115 | else "", 116 | } 117 | 118 | # Get full content if available 119 | content_element = item.find( 120 | ".//{http://purl.org/rss/1.0/modules/content/}encoded" 121 | ) 122 | if content_element is not None and content_element.text: 123 | story["content"] = content_element.text 124 | # Extract Twitter recap items 125 | story["twitter_recap"] = extract_twitter_recap(content_element.text) 126 | else: 127 | story["content"] = "" 128 | story["twitter_recap"] = [] 129 | 130 | # Extract categories if available 131 | categories = item.findall("category") 132 | if categories: 133 | story["categories"] = [cat.text for cat in categories if cat.text] 134 | else: 135 | story["categories"] = [] 136 | 137 | stories.append(story) 138 | 139 | return stories 140 | except ET.ParseError as e: 141 | return [{"error": f"Error parsing XML: {str(e)}"}] 142 | except Exception as e: 143 | return [{"error": f"Error parsing RSS: {str(e)}"}] 144 | 145 | 146 | def format_ainews_story(story: Dict[str, Any]) -> str: 147 | """ 148 | Format an AI News story into a readable string. 149 | 150 | Args: 151 | story: Dictionary containing article data 152 | 153 | Returns: 154 | Formatted article string 155 | """ 156 | # Check if this is an error message 157 | if "error" in story: 158 | return f"ERROR: {story['error']}" 159 | 160 | # Format the article 161 | title = story.get("title", "Unknown Title") 162 | link = story.get("link", "No link available") 163 | pub_date = story.get("pubDate", "Unknown publication date") 164 | description = story.get("description", "No description available") 165 | 166 | # Build the formatted string with the new order 167 | formatted = f""" 168 | Title: {title} 169 | Link: {link} 170 | Description: {description} 171 | Published: {pub_date} 172 | """ 173 | 174 | # Add Twitter recap if available, but without the header 175 | twitter_recap = story.get("twitter_recap", []) 176 | if twitter_recap: 177 | formatted += "\n\n" # Add space but no header 178 | for item in twitter_recap: 179 | formatted += f"Title: {item['title']}\nLink: {item['link']}\nDescription: {item['description']}\n\n" 180 | 181 | # Add categories if available 182 | categories = story.get("categories", []) 183 | if categories: 184 | formatted += f"\nCategories: {', '.join(categories)}" 185 | 186 | return formatted 187 | -------------------------------------------------------------------------------- /src/hackernews.py: -------------------------------------------------------------------------------- 1 | import xml.etree.ElementTree as ET 2 | from typing import Any, Dict, List 3 | 4 | import httpx 5 | 6 | # Constants 7 | DEFAULT_HN_RSS_URL = "https://news.ycombinator.com/rss" 8 | USER_AGENT = "hackernews-reader/1.0" 9 | 10 | 11 | async def fetch_hn_rss(feed_url: str) -> str: 12 | """ 13 | Fetch Hacker News RSS feed. 14 | 15 | Args: 16 | feed_url: URL of the RSS feed to fetch (defaults to Hacker News) 17 | """ 18 | headers = {"User-Agent": USER_AGENT} 19 | async with httpx.AsyncClient() as client: 20 | try: 21 | response = await client.get(feed_url, headers=headers, timeout=10.0) 22 | response.raise_for_status() 23 | return response.text 24 | except httpx.HTTPError as e: 25 | return f"HTTP Error fetching RSS: {str(e)}" 26 | except httpx.TimeoutException: 27 | return f"Timeout fetching RSS from {feed_url}" 28 | except Exception as e: 29 | return f"Error fetching RSS: {str(e)}" 30 | 31 | 32 | def parse_hn_rss(rss_content: str) -> List[Dict[str, Any]]: 33 | """Parse RSS content into a list of story dictionaries.""" 34 | stories = [] 35 | try: 36 | root = ET.fromstring(rss_content) 37 | items = root.findall(".//item") 38 | 39 | for item in items: 40 | story = { 41 | "title": item.find("title").text 42 | if item.find("title") is not None 43 | else "No title", 44 | "link": item.find("link").text if item.find("link") is not None else "", 45 | "description": item.find("description").text 46 | if item.find("description") is not None 47 | else "No description", 48 | "pubDate": item.find("pubDate").text 49 | if item.find("pubDate") is not None 50 | else "", 51 | # Any other fields we want to extract 52 | } 53 | stories.append(story) 54 | 55 | return stories 56 | except Exception as e: 57 | return [{"error": f"Error parsing RSS: {str(e)}"}] 58 | 59 | 60 | def format_hn_story(story: Dict[str, Any]) -> str: 61 | """Format a story into a readable string.""" 62 | formatted = f""" 63 | Title: {story.get("title", "Unknown")} 64 | Link: {story.get("link", "No link")} 65 | Published: {story.get("pubDate", "Unknown")} 66 | """ 67 | 68 | return formatted 69 | -------------------------------------------------------------------------------- /src/main.py: -------------------------------------------------------------------------------- 1 | from mcp.server.fastmcp import FastMCP 2 | 3 | from ainews import ( 4 | DEFAULT_AINEWS_RSS_URL, 5 | fetch_ainews_rss, 6 | format_ainews_story, 7 | parse_ainews_rss, 8 | ) 9 | from hackernews import DEFAULT_HN_RSS_URL, fetch_hn_rss, format_hn_story, parse_hn_rss 10 | from techcrunch import DEFAULT_TC_RSS_URL, fetch_tc_rss, format_tc_story, parse_tc_rss 11 | from wired import ( 12 | DEFAULT_WIRED_RSS_URL, 13 | fetch_wired_rss, 14 | format_wired_story, 15 | parse_wired_rss, 16 | ) 17 | from wsj import DEFAULT_WSJ_RSS_URL, fetch_wsj_rss, format_wsj_story, parse_wsj_rss 18 | 19 | # Initialize FastMCP server 20 | mcp = FastMCP("news-mcp") 21 | 22 | 23 | @mcp.tool() 24 | async def get_hackernews_stories( 25 | feed_url: str = DEFAULT_HN_RSS_URL, count: int = 30 26 | ) -> str: 27 | """Get top stories from Hacker News. 28 | 29 | Args: 30 | feed_url: URL of the RSS feed to use (default: Hacker News) 31 | count: Number of stories to return (default: 5) 32 | """ 33 | rss_content = await fetch_hn_rss(feed_url) 34 | if rss_content.startswith("Error"): 35 | return rss_content 36 | 37 | stories = parse_hn_rss(rss_content) 38 | 39 | # Limit to requested count 40 | stories = stories[: min(count, len(stories))] 41 | 42 | if not stories: 43 | return "No stories found." 44 | 45 | formatted_stories = [format_hn_story(story) for story in stories] 46 | return "\n---\n".join(formatted_stories) 47 | 48 | 49 | @mcp.tool() 50 | async def get_wallstreetjournal_stories( 51 | feed_url: str = DEFAULT_WSJ_RSS_URL, count: int = 30 52 | ) -> str: 53 | """Get stories from Wall Street Journal. 54 | 55 | Args: 56 | feed_url: URL of the WSJ RSS feed to use 57 | count: Number of stories to return (default: 5) 58 | """ 59 | # Fetch the content 60 | rss_content = await fetch_wsj_rss(feed_url) 61 | if rss_content.startswith("Error"): 62 | return rss_content 63 | 64 | stories = parse_wsj_rss(rss_content) 65 | 66 | # Check for errors in parsing 67 | if stories and "error" in stories[0]: 68 | return stories[0]["error"] 69 | 70 | # Limit to requested count 71 | stories = stories[: min(count, len(stories))] 72 | 73 | if not stories: 74 | return "No stories found." 75 | 76 | formatted_stories = [format_wsj_story(story) for story in stories] 77 | return "\n---\n".join(formatted_stories) 78 | 79 | 80 | @mcp.tool() 81 | async def get_techcrunch_stories( 82 | feed_url: str = DEFAULT_TC_RSS_URL, count: int = 30 83 | ) -> str: 84 | """Get stories from TechCrunch. 85 | 86 | Args: 87 | feed_url: URL of the TechCrunch RSS feed to use 88 | count: Number of stories to return (default: 30) 89 | """ 90 | # Fetch the content 91 | rss_content = await fetch_tc_rss(feed_url) 92 | if rss_content.startswith("Error"): 93 | return rss_content 94 | 95 | stories = parse_tc_rss(rss_content) 96 | 97 | # Check for errors in parsing 98 | if stories and "error" in stories[0]: 99 | return stories[0]["error"] 100 | 101 | # Limit to requested count 102 | stories = stories[: min(count, len(stories))] 103 | 104 | if not stories: 105 | return "No stories found." 106 | 107 | formatted_stories = [format_tc_story(story) for story in stories] 108 | return "\n---\n".join(formatted_stories) 109 | 110 | 111 | @mcp.tool() 112 | async def get_ainews_latest(feed_url: str = DEFAULT_AINEWS_RSS_URL) -> str: 113 | """Get the latest story from AI News. 114 | 115 | Args: 116 | feed_url: URL of the AI News RSS feed to use (default: AI News) 117 | """ 118 | # Fetch the content 119 | rss_content = await fetch_ainews_rss(feed_url) 120 | if rss_content.startswith("Error"): 121 | return rss_content 122 | 123 | stories = parse_ainews_rss(rss_content) 124 | 125 | # Check for errors in parsing 126 | if stories and "error" in stories[0]: 127 | return stories[0]["error"] 128 | 129 | if not stories: 130 | return "No stories found." 131 | 132 | # Only format the latest story 133 | return format_ainews_story(stories[0]) 134 | 135 | 136 | @mcp.tool() 137 | async def get_wired_stories( 138 | feed_url: str = DEFAULT_WIRED_RSS_URL, count: int = 30 139 | ) -> str: 140 | """Get AI stories from Wired. 141 | 142 | Args: 143 | feed_url: URL of the Wired RSS feed to use (default: Wired AI feed) 144 | count: Number of stories to return (default: 30) 145 | """ 146 | # Fetch the content 147 | rss_content = await fetch_wired_rss(feed_url) 148 | if rss_content.startswith("Error"): 149 | return rss_content 150 | 151 | stories = parse_wired_rss(rss_content) 152 | 153 | # Check for errors in parsing 154 | if stories and "error" in stories[0]: 155 | return stories[0]["error"] 156 | 157 | # Limit to requested count 158 | stories = stories[: min(count, len(stories))] 159 | 160 | if not stories: 161 | return "No stories found." 162 | 163 | formatted_stories = [format_wired_story(story) for story in stories] 164 | return "\n---\n".join(formatted_stories) 165 | 166 | 167 | if __name__ == "__main__": 168 | # Initialize and run the server 169 | mcp.run(transport="stdio") 170 | -------------------------------------------------------------------------------- /src/techcrunch.py: -------------------------------------------------------------------------------- 1 | import xml.etree.ElementTree as ET 2 | from typing import Any, Dict, List 3 | 4 | import httpx 5 | 6 | # Register XML namespaces to make parsing cleaner 7 | ET.register_namespace("content", "http://purl.org/rss/1.0/modules/content/") 8 | ET.register_namespace("wfw", "http://wellformedweb.org/CommentAPI/") 9 | ET.register_namespace("dc", "http://purl.org/dc/elements/1.1/") 10 | ET.register_namespace("atom", "http://www.w3.org/2005/Atom") 11 | ET.register_namespace("sy", "http://purl.org/rss/1.0/modules/syndication/") 12 | ET.register_namespace("slash", "http://purl.org/rss/1.0/modules/slash/") 13 | 14 | # Constants 15 | DEFAULT_TC_RSS_URL = "https://techcrunch.com/feed/" 16 | USER_AGENT = "techcrunch-reader/1.0" 17 | 18 | 19 | async def fetch_tc_rss(feed_url: str) -> str: 20 | """ 21 | Fetch TechCrunch RSS feed. 22 | 23 | Args: 24 | feed_url: URL to fetch (defaults to TechCrunch main feed) 25 | 26 | Returns: 27 | RSS content as string or error message 28 | """ 29 | headers = {"User-Agent": USER_AGENT} 30 | async with httpx.AsyncClient() as client: 31 | try: 32 | response = await client.get(feed_url, headers=headers, timeout=10.0) 33 | response.raise_for_status() 34 | return response.text 35 | except httpx.HTTPError as e: 36 | return f"HTTP Error fetching RSS: {str(e)}" 37 | except httpx.TimeoutException: 38 | return f"Timeout fetching RSS from {feed_url}" 39 | except Exception as e: 40 | return f"Error fetching RSS: {str(e)}" 41 | 42 | 43 | def parse_tc_rss(rss_content: str) -> List[Dict[str, Any]]: 44 | """ 45 | Parse TechCrunch RSS content into a list of article dictionaries. 46 | 47 | Args: 48 | rss_content: RSS XML content as string 49 | 50 | Returns: 51 | List of dictionaries containing article data 52 | """ 53 | articles = [] 54 | try: 55 | root = ET.fromstring(rss_content) 56 | channel = root.find("channel") 57 | 58 | # Check if we found a channel 59 | if channel is None: 60 | return [{"error": "Invalid RSS format: No channel element found"}] 61 | 62 | items = channel.findall("item") 63 | 64 | for item in items: 65 | article = {} 66 | 67 | # Required fields (with fallbacks) 68 | article["title"] = get_element_text(item, "title", "No title") 69 | article["link"] = get_element_text(item, "link", "") 70 | article["pubDate"] = get_element_text(item, "pubDate", "") 71 | article["description"] = get_element_text( 72 | item, "description", "No description" 73 | ) 74 | 75 | # Handle author (dc:creator) 76 | author = item.find(".//{http://purl.org/dc/elements/1.1/}creator") 77 | article["author"] = ( 78 | author.text if author is not None and author.text else "" 79 | ) 80 | 81 | # Handle GUID 82 | guid_element = item.find("guid") 83 | if guid_element is not None: 84 | article["guid"] = guid_element.text or "" 85 | article["guid_permalink"] = guid_element.attrib.get( 86 | "isPermaLink", "false" 87 | ) 88 | else: 89 | article["guid"] = "" 90 | article["guid_permalink"] = "false" 91 | 92 | # Handle multiple categories 93 | categories = item.findall("category") 94 | if categories: 95 | article["categories"] = [cat.text for cat in categories if cat.text] 96 | else: 97 | article["categories"] = [] 98 | 99 | articles.append(article) 100 | 101 | return articles 102 | except ET.ParseError as e: 103 | return [{"error": f"Error parsing XML: {str(e)}"}] 104 | except Exception as e: 105 | return [{"error": f"Error parsing RSS: {str(e)}"}] 106 | 107 | 108 | def get_element_text(element, tag, default=""): 109 | """Helper function to safely extract element text.""" 110 | el = element.find(tag) 111 | return el.text if el is not None and el.text else default 112 | 113 | 114 | def format_tc_story(story: Dict[str, Any]) -> str: 115 | """ 116 | Format a TechCrunch story into a readable string. 117 | 118 | Args: 119 | story: Dictionary containing article data 120 | 121 | Returns: 122 | Formatted article string 123 | """ 124 | # Check if this is an error message 125 | if "error" in story: 126 | return f"ERROR: {story['error']}" 127 | 128 | # Format the article 129 | title = story.get("title", "Unknown Title") 130 | link = story.get("link", "No link available") 131 | pub_date = story.get("pubDate", "Unknown publication date") 132 | description = story.get("description", "No description available") 133 | author = story.get("author", "") 134 | categories = story.get("categories", []) 135 | 136 | # Build the formatted string 137 | formatted = f""" 138 | Title: {title} 139 | Link: {link}""" 140 | 141 | if author: 142 | formatted += f"\nAuthor: {author}" 143 | 144 | formatted += f"\nPublished: {pub_date}" 145 | 146 | if categories: 147 | formatted += f"\nCategories: {', '.join(categories)}" 148 | 149 | formatted += f"\n\n{description}\n" 150 | 151 | return formatted 152 | -------------------------------------------------------------------------------- /src/wired.py: -------------------------------------------------------------------------------- 1 | import xml.etree.ElementTree as ET 2 | from typing import Any, Dict, List 3 | 4 | import httpx 5 | 6 | # Register XML namespaces 7 | ET.register_namespace("atom", "http://www.w3.org/2005/Atom") 8 | ET.register_namespace("dc", "http://purl.org/dc/elements/1.1/") 9 | ET.register_namespace("media", "http://search.yahoo.com/mrss/") 10 | 11 | # Constants 12 | DEFAULT_WIRED_RSS_URL = "https://www.wired.com/feed/tag/ai/latest/rss" 13 | USER_AGENT = "wired-reader/1.0" 14 | 15 | 16 | async def fetch_wired_rss(feed_url: str = DEFAULT_WIRED_RSS_URL) -> str: 17 | """ 18 | Fetch Wired AI RSS feed. 19 | 20 | Args: 21 | feed_url: URL of the RSS feed to fetch (defaults to Wired AI feed) 22 | 23 | Returns: 24 | RSS content as string or error message 25 | """ 26 | headers = {"User-Agent": USER_AGENT} 27 | async with httpx.AsyncClient() as client: 28 | try: 29 | response = await client.get(feed_url, headers=headers, timeout=10.0) 30 | response.raise_for_status() 31 | return response.text 32 | except httpx.HTTPError as e: 33 | return f"HTTP Error fetching RSS: {str(e)}" 34 | except httpx.TimeoutException: 35 | return f"Timeout fetching RSS from {feed_url}" 36 | except Exception as e: 37 | return f"Error fetching RSS: {str(e)}" 38 | 39 | 40 | def parse_wired_rss(rss_content: str) -> List[Dict[str, Any]]: 41 | """ 42 | Parse Wired RSS content into a list of article dictionaries. 43 | 44 | Args: 45 | rss_content: RSS XML content as string 46 | 47 | Returns: 48 | List of dictionaries containing article data 49 | """ 50 | articles = [] 51 | try: 52 | root = ET.fromstring(rss_content) 53 | channel = root.find("channel") 54 | 55 | # Check if we found a channel 56 | if channel is None: 57 | return [{"error": "Invalid RSS format: No channel element found"}] 58 | 59 | items = channel.findall("item") 60 | 61 | for item in items: 62 | article = {} 63 | 64 | # Basic fields 65 | article["title"] = get_element_text(item, "title", "No title") 66 | article["link"] = get_element_text(item, "link", "") 67 | article["pubDate"] = get_element_text(item, "pubDate", "") 68 | article["description"] = get_element_text( 69 | item, "description", "No description" 70 | ) 71 | article["guid"] = get_element_text(item, "guid", "") 72 | 73 | # DC fields (author) 74 | creator = item.find(".//{http://purl.org/dc/elements/1.1/}creator") 75 | article["author"] = ( 76 | creator.text if creator is not None and creator.text else "" 77 | ) 78 | 79 | # DC subject (section) 80 | subject = item.find(".//{http://purl.org/dc/elements/1.1/}subject") 81 | article["subject"] = ( 82 | subject.text if subject is not None and subject.text else "" 83 | ) 84 | 85 | # Handle multiple categories 86 | categories = item.findall("category") 87 | if categories: 88 | article["categories"] = [cat.text for cat in categories if cat.text] 89 | else: 90 | article["categories"] = [] 91 | 92 | # Media thumbnail 93 | thumbnail = item.find(".//{http://search.yahoo.com/mrss/}thumbnail") 94 | if thumbnail is not None and "url" in thumbnail.attrib: 95 | article["image_url"] = thumbnail.attrib["url"] 96 | article["image_width"] = thumbnail.attrib.get("width", "") 97 | article["image_height"] = thumbnail.attrib.get("height", "") 98 | else: 99 | article["image_url"] = "" 100 | article["image_width"] = "" 101 | article["image_height"] = "" 102 | 103 | articles.append(article) 104 | 105 | return articles 106 | except ET.ParseError as e: 107 | return [{"error": f"Error parsing XML: {str(e)}"}] 108 | except Exception as e: 109 | return [{"error": f"Error parsing RSS: {str(e)}"}] 110 | 111 | 112 | def get_element_text(element, tag, default=""): 113 | """Helper function to safely extract element text.""" 114 | el = element.find(tag) 115 | return el.text if el is not None and el.text else default 116 | 117 | 118 | def format_wired_story(story: Dict[str, Any]) -> str: 119 | """ 120 | Format a Wired story into a readable string. 121 | 122 | Args: 123 | story: Dictionary containing article data 124 | 125 | Returns: 126 | Formatted article string 127 | """ 128 | # Check if this is an error message 129 | if "error" in story: 130 | return f"ERROR: {story['error']}" 131 | 132 | # Format the article 133 | title = story.get("title", "Unknown Title") 134 | link = story.get("link", "No link available") 135 | pub_date = story.get("pubDate", "Unknown publication date") 136 | description = story.get("description", "No description available") 137 | author = story.get("author", "") 138 | subject = story.get("subject", "") 139 | categories = story.get("categories", []) 140 | 141 | # Build the formatted string 142 | formatted = f""" 143 | Title: {title} 144 | Link: {link}""" 145 | 146 | if author: 147 | formatted += f"\nAuthor: {author}" 148 | 149 | if subject: 150 | formatted += f"\nSubject: {subject}" 151 | 152 | formatted += f"\nPublished: {pub_date}" 153 | 154 | if categories: 155 | formatted += f"\nCategories: {', '.join(categories)}" 156 | 157 | formatted += f"\n\n{description}\n" 158 | 159 | return formatted 160 | -------------------------------------------------------------------------------- /src/wsj.py: -------------------------------------------------------------------------------- 1 | import xml.etree.ElementTree as ET 2 | from typing import Any, Dict, List 3 | 4 | import httpx 5 | 6 | # Register XML namespaces to make parsing cleaner 7 | ET.register_namespace("media", "http://search.yahoo.com/mrss/") 8 | ET.register_namespace("dc", "http://purl.org/dc/elements/1.1/") 9 | ET.register_namespace("content", "http://purl.org/rss/1.0/modules/content/") 10 | 11 | # Constants 12 | DEFAULT_WSJ_RSS_URL = "https://feeds.content.dowjones.io/public/rss/RSSWSJD" 13 | USER_AGENT = "wsj-reader/1.0" 14 | 15 | 16 | async def fetch_wsj_rss(feed_url: str) -> str: 17 | """ 18 | Fetch Wall Street Journal RSS feed. 19 | 20 | Args: 21 | feed_url: URL to fetch 22 | 23 | Returns: 24 | RSS content as string or error message 25 | """ 26 | headers = {"User-Agent": USER_AGENT} 27 | async with httpx.AsyncClient() as client: 28 | try: 29 | response = await client.get(feed_url, headers=headers, timeout=10.0) 30 | response.raise_for_status() 31 | return response.text 32 | except httpx.HTTPError as e: 33 | return f"HTTP Error fetching RSS: {str(e)}" 34 | except httpx.TimeoutException: 35 | return f"Timeout fetching RSS from {feed_url}" 36 | except Exception as e: 37 | return f"Error fetching RSS: {str(e)}" 38 | 39 | 40 | def parse_wsj_rss(rss_content: str) -> List[Dict[str, Any]]: 41 | """ 42 | Parse RSS content into a list of article dictionaries. 43 | 44 | Args: 45 | rss_content: RSS XML content as string 46 | 47 | Returns: 48 | List of dictionaries containing article data 49 | """ 50 | articles = [] 51 | try: 52 | root = ET.fromstring(rss_content) 53 | channel = root.find("channel") 54 | 55 | # Check if we found a channel 56 | if channel is None: 57 | return [{"error": "Invalid RSS format: No channel element found"}] 58 | 59 | items = channel.findall("item") 60 | 61 | for item in items: 62 | # Extract all common fields 63 | article = {} 64 | 65 | # Required fields (with fallbacks) 66 | article["title"] = get_element_text(item, "title", "No title") 67 | article["link"] = get_element_text(item, "link", "") 68 | article["pubDate"] = get_element_text(item, "pubDate", "") 69 | article["description"] = get_element_text( 70 | item, "description", "No description" 71 | ) 72 | 73 | # Handle multiple authors (dc:creator elements) 74 | authors = item.findall(".//{http://purl.org/dc/elements/1.1/}creator") 75 | if authors: 76 | article["author"] = ", ".join([a.text for a in authors if a.text]) 77 | else: 78 | article["author"] = "" 79 | 80 | article["guid"] = get_element_text(item, "guid", "") 81 | article["category"] = get_element_text(item, "category", "") 82 | 83 | # Optional WSJ-specific field for article ID 84 | article["id"] = get_element_text(item, "id", "") 85 | 86 | # Extract image URL if available 87 | article["image_url"] = extract_image_url(item) 88 | 89 | articles.append(article) 90 | 91 | return articles 92 | except ET.ParseError as e: 93 | return [{"error": f"Error parsing XML: {str(e)}"}] 94 | except Exception as e: 95 | return [{"error": f"Error parsing RSS: {str(e)}"}] 96 | 97 | 98 | def get_element_text(element, tag, default=""): 99 | """Helper function to safely extract element text.""" 100 | # Handle both regular tags and namespaced tags 101 | el = element.find(tag) 102 | 103 | # Look for namespaced tags 104 | if el is None: 105 | # Handle specific namespaces 106 | if tag == "creator": 107 | el = element.find(".//{http://purl.org/dc/elements/1.1/}creator") 108 | else: 109 | # Try various namespace paths 110 | el = element.find(f"*//{tag}") 111 | 112 | return el.text if el is not None and el.text else default 113 | 114 | 115 | def extract_image_url(item: ET.Element) -> str: 116 | """Extract image URL from various possible elements.""" 117 | # Try different possible locations for image 118 | media_content = item.find(".//{http://search.yahoo.com/mrss/}content") 119 | if media_content is not None and "url" in media_content.attrib: 120 | return media_content.attrib["url"] 121 | 122 | media_thumbnail = item.find(".//{http://search.yahoo.com/mrss/}thumbnail") 123 | if media_thumbnail is not None and "url" in media_thumbnail.attrib: 124 | return media_thumbnail.attrib["url"] 125 | 126 | enclosure = item.find("enclosure") 127 | if enclosure is not None and "url" in enclosure.attrib: 128 | return enclosure.attrib["url"] 129 | 130 | return "" 131 | 132 | 133 | def format_wsj_story(story: Dict[str, Any]) -> str: 134 | """ 135 | Format a WSJ story into a readable string. 136 | 137 | Args: 138 | story: Dictionary containing article data 139 | 140 | Returns: 141 | Formatted article string 142 | """ 143 | # Check if this is an error message 144 | if "error" in story: 145 | return f"ERROR: {story['error']}" 146 | 147 | # Format the article 148 | title = story.get("title", "Unknown Title") 149 | link = story.get("link", "No link available") 150 | pub_date = story.get("pubDate", "Unknown publication date") 151 | description = story.get("description", "No description available") 152 | author = story.get("author", "") 153 | 154 | # Build the formatted string 155 | formatted = f""" 156 | Title: {title} 157 | Link: {link}""" 158 | 159 | if author: 160 | formatted += f"\nAuthor: {author}" 161 | 162 | formatted += f""" 163 | Published: {pub_date} 164 | 165 | {description} 166 | """ 167 | 168 | return formatted 169 | -------------------------------------------------------------------------------- /summaries/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eugeneyan/news-agents/6af170d3089a15ea78e505d0a95839c85fd159f9/summaries/.gitkeep -------------------------------------------------------------------------------- /summaries/ainews-summary.md: -------------------------------------------------------------------------------- 1 | # AI News Feed 2 | Date: 2025-05-04 3 | 4 | ## Complete Item List 5 | 6 | ### Item 1: Not much happened today 7 | - **Link:** https://news.smol.ai/issues/25-05-02-not-much/ 8 | - **Category:** AI Model Updates 9 | 10 | ### Item 2: Qwen Model Family 11 | - **Link:** https://twitter.com/Alibaba_Qwen/status/1918353505074725363 12 | - **Category:** Model Release 13 | 14 | ### Item 3: Phi Models 15 | - **Link:** https://twitter.com/_philschmid/status/1918216082231320632 16 | - **Category:** Model Release 17 | 18 | ### Item 4: Command A SQL Performance 19 | - **Link:** https://twitter.com/cohere/status/1918386633772286278 20 | - **Category:** Model Performance 21 | 22 | ### Item 5: Gemini and Vertex AI 23 | - **Link:** https://twitter.com/arankomatsuzaki/status/1918148050671026336 24 | - **Category:** Evaluation Tools 25 | 26 | ### Item 6: Diffusion Models 27 | - **Link:** https://twitter.com/ArtificialAnlys/status/1917830734334812541 28 | - **Category:** Model Architecture 29 | 30 | ### Item 7: LM Arena 31 | - **Link:** https://twitter.com/lmarena_ai/status/1917959763284894159 32 | - **Category:** Model Evaluation 33 | 34 | ### Item 8: Other Models 35 | - **Link:** https://twitter.com/reach_vb/status/1917852036369916081 36 | - **Category:** Model Release 37 | 38 | ### Item 9: General Model Eval 39 | - **Link:** https://twitter.com/cloneofsimo/status/1917888990721749065 40 | - **Category:** Model Evaluation 41 | 42 | ### Item 10: Agent-to-Agent (A2A) Collaboration 43 | - **Link:** https://twitter.com/TheTuringPost/status/1918259844001480874 44 | - **Category:** AI Agents 45 | 46 | ### Item 11: Agent Leaderboard 47 | - **Link:** https://twitter.com/omarsar0/status/1917939469103305013 48 | - **Category:** AI Agents 49 | 50 | ### Item 12: Multi-Step Learning for Agents 51 | - **Link:** https://twitter.com/TheTuringPost/status/1918093128843870288 52 | - **Category:** AI Agents 53 | 54 | ### Item 13: Agent Memory 55 | - **Link:** https://twitter.com/omarsar0/status/1918308774823264416 56 | - **Category:** AI Agents 57 | 58 | ### Item 14: LlamaIndex for Agentic Workflows 59 | - **Link:** https://twitter.com/llama_index/status/1917965350848884770 60 | - **Category:** AI Tools 61 | 62 | ### Item 15: Cline and MCPs 63 | - **Link:** https://twitter.com/swyx/status/1917999320055582948 64 | - **Category:** AI Tools 65 | 66 | ### Item 16: AI-Enabled Education 67 | - **Link:** https://twitter.com/AndrewYNg/status/1917985792607363189 68 | - **Category:** AI Applications 69 | 70 | ### Item 17: AI in Financial Services 71 | - **Link:** https://twitter.com/cohere/status/1917996900487401964 72 | - **Category:** AI Applications 73 | 74 | ### Item 18: AI-Driven Customer Insight 75 | - **Link:** https://twitter.com/RamaswmySridhar/status/1917982790282559946 76 | - **Category:** AI Applications 77 | 78 | ### Item 19: AI in Healthcare 79 | - **Link:** https://twitter.com/GlassHealthHQ/status/1917938798224183695 80 | - **Category:** AI Applications 81 | 82 | ### Item 20: AI for Text Summarization 83 | - **Link:** https://twitter.com/TheTuringPost/status/1917990621501112799 84 | - **Category:** AI Research 85 | 86 | ### Item 21: RunwayML Gen-4 References 87 | - **Link:** https://twitter.com/c_valenzuelab/status/1918282729654755492 88 | - **Category:** AI Tools 89 | 90 | ### Item 22: Llama Impact Grants 91 | - **Link:** https://twitter.com/AIatMeta/status/1917727629601616030 92 | - **Category:** AI Funding 93 | 94 | ### Item 23: HF Community 95 | - **Link:** https://twitter.com/ClementDelangue/status/1918038543772897739 96 | - **Category:** Community 97 | 98 | ### Item 24: Community Building 99 | - **Link:** https://twitter.com/omarsar0/status/1918350504611979663 100 | - **Category:** Community 101 | 102 | ### Item 25: The Future of LLM GUIs 103 | - **Link:** https://twitter.com/karpathy/status/1917920257257459899 104 | - **Category:** AI UX/UI 105 | 106 | ### Item 26: AI and Job Displacement 107 | - **Link:** https://twitter.com/fchollet/status/1918258519624790273 108 | - **Category:** AI Impact 109 | 110 | ### Item 27: AI for the Unbanked 111 | - **Link:** https://twitter.com/AIatMeta/status/1917727629601616030 112 | - **Category:** AI Applications 113 | 114 | ### Item 28: Agent Chat UI 115 | - **Link:** https://twitter.com/LangChainAI/status/1917973237478408255 116 | - **Category:** AI UX/UI 117 | 118 | ### Item 29: Kling AI 119 | - **Link:** https://twitter.com/Kling_ai/status/1917873972429111341 120 | - **Category:** AI Products 121 | 122 | ### Item 30: @Darthstinkywink Fucking fire says @dylan522p 123 | - **Link:** https://twitter.com/dylan522p/status/1917744454829592747 124 | - **Category:** Community Reactions 125 | 126 | ### Item 31: "Senior programmers" are laughing at me, but I'm already a 10x engineer, now becoming a 10x prompter, says @Yuchenj_UW 127 | - **Link:** https://twitter.com/Yuchenj_UW/status/1918349440072716502 128 | - **Category:** Community Reactions 129 | 130 | ### Item 32: @teortaxesTex says "Literally a nothingburger, Palmer can keep sleeping" 131 | - **Link:** https://twitter.com/teortaxesTex/status/1918363762748264887 132 | - **Category:** Community Reactions 133 | 134 | ### Item 33: @Teknium1 says they couldn't just give it to everyone right now, lol 135 | - **Link:** https://twitter.com/Teknium1/status/1917770525277052937 136 | - **Category:** Community Reactions 137 | 138 | ### Item 34: @scaling01 says GPT-4o is honestly weird, like a liberal Gen-Z girl persona 139 | - **Link:** https://twitter.com/scaling01/status/1918124943985778924 140 | - **Category:** Community Reactions 141 | 142 | --- 143 | 144 | ## Summary and Top Trends 145 | 146 | ### Key Statistics 147 | - **Total Items Processed:** 34 148 | - **Sources Covered:** Multiple (Twitter, news.smol.ai) 149 | - **Categories Identified:** Model Release, Model Performance, Model Evaluation, AI Agents, AI Tools, AI Applications, AI Research, Community, AI UX/UI, AI Impact, Community Reactions 150 | 151 | ### Top 3 Emerging Trends 152 | 153 | 1. **Large Model Quantization and Efficiency** 154 | - Frequency: 5 items related to this trend 155 | - Key development: Release of quantized versions of large models (Qwen3 family) and new efficient models like Phi-4-reasoning 156 | - Representative examples: Items 1, 2, 3, 6, 8 157 | 158 | 2. **Agent-to-Agent Collaboration and Memory Systems** 159 | - Frequency: 6 items related to this trend 160 | - Key development: Google's A2A protocol enabling interoperable agents and advancements in agent memory systems 161 | - Representative examples: Items 10, 11, 12, 13, 14, 15 162 | 163 | 3. **Industry-Specific AI Applications** 164 | - Frequency: 5 items related to this trend 165 | - Key development: Specialized AI implementations across education, finance, healthcare, and customer insights 166 | - Representative examples: Items 16, 17, 18, 19, 27 167 | 168 | ### Notable Outliers 169 | - Inception Labs' diffusion LLM API claiming 5x faster speeds than autoregressive models represents a potentially significant architectural shift 170 | - Karpathy's comments on the future of LLM GUIs suggest upcoming innovations in how users interact with AI systems 171 | 172 | ### Summary Insight 173 | The AI landscape continues to evolve with a dual focus on making large models more efficient through quantization and distillation techniques, while simultaneously advancing agent capabilities through improved collaboration protocols and memory systems. Industry-specific applications are maturing rapidly, with particular momentum in healthcare, education, and financial services sectors, suggesting AI's practical utility is expanding beyond research environments. 174 | -------------------------------------------------------------------------------- /summaries/hackernews-summary.md: -------------------------------------------------------------------------------- 1 | # Hacker News 2 | Date: May 4, 2025 3 | 4 | ## Complete Item List 5 | 6 | ### Item 1: Design for 3D-Printing 7 | - **Link:** https://blog.rahix.de/design-for-3d-printing/ 8 | - **Category:** Engineering/Manufacturing 9 | 10 | ### Item 2: TScale – distributed training on consumer GPUs 11 | - **Link:** https://github.com/Foreseerr/TScale 12 | - **Category:** Machine Learning/AI 13 | 14 | ### Item 3: Critical Program Reading (1975) [video] 15 | - **Link:** https://www.youtube.com/watch?v=7hdJQkn8rtA 16 | - **Category:** Computer Science/Programming History 17 | 18 | ### Item 4: The Alabama Landline That Keeps Ringing 19 | - **Link:** https://oxfordamerican.org/oa-now/the-alabama-landline-that-keeps-ringing 20 | - **Category:** Culture/Technology History 21 | 22 | ### Item 5: Load-Store Conflicts 23 | - **Link:** https://zeux.io/2025/05/03/load-store-conflicts/ 24 | - **Category:** Computer Architecture/Programming 25 | 26 | ### Item 6: Feather: A web framework that skips Rust's async boilerplate 27 | - **Link:** https://github.com/BersisSe/feather 28 | - **Category:** Programming/Web Development 29 | 30 | ### Item 7: In kids, EEG monitoring of consciousness safely reduces anesthetic use 31 | - **Link:** https://news.mit.edu/2025/kids-eeg-monitoring-consciousness-safely-reduces-anesthetic-use-0429 32 | - **Category:** Healthcare/Medical Technology 33 | 34 | ### Item 8: Dummy's Guide to Modern LLM Sampling 35 | - **Link:** https://rentry.co/samplers 36 | - **Category:** AI/Machine Learning 37 | 38 | ### Item 9: Hightouch (YC S19) Is Hiring 39 | - **Link:** https://www.ycombinator.com/companies/hightouch/jobs/kIoY0yH-machine-learning-engineer-ai-decisioning 40 | - **Category:** Job Posting/Startup 41 | 42 | ### Item 10: Oberon Pi 43 | - **Link:** http://pascal.hansotten.com/niklaus-wirth/project-oberon/oberon-pi/ 44 | - **Category:** Programming Languages/Systems 45 | 46 | ### Item 11: Show HN: EZ-TRAK Satellite Hand Tracking Suite 47 | - **Link:** https://github.com/benb0jangles/EzTrak 48 | - **Category:** Hardware/Software Project 49 | 50 | ### Item 12: Gorgeous-GRUB: collection of decent community-made GRUB themes 51 | - **Link:** https://github.com/Jacksaur/Gorgeous-GRUB 52 | - **Category:** System Customization/Open Source 53 | 54 | ### Item 13: Show HN: Free, in-browser PDF editor 55 | - **Link:** https://breezepdf.com 56 | - **Category:** Web Tools/Productivity 57 | 58 | ### Item 14: The Speed of VITs and CNNs 59 | - **Link:** https://lucasb.eyer.be/articles/vit_cnn_speed.html 60 | - **Category:** Machine Learning/Computer Vision 61 | 62 | ### Item 15: DuckDB is probably the most important geospatial software of the last decade 63 | - **Link:** https://www.dbreunig.com/2025/05/03/duckdb-is-the-most-impactful-geospatial-software-in-a-decade.html 64 | - **Category:** Database/Geospatial Technology 65 | 66 | ### Item 16: What went wrong with wireless USB 67 | - **Link:** http://oldvcr.blogspot.com/2025/05/what-went-wrong-with-wireless-usb.html 68 | - **Category:** Hardware/Technology History 69 | 70 | ### Item 17: Show HN: MP3 File Editor for Bulk Processing 71 | - **Link:** https://cjmapp.net/ 72 | - **Category:** Audio Tools/Software 73 | 74 | ### Item 18: Tippy Coco: A Free, Open-Source Game Inspired by Slime Volleyball 75 | - **Link:** https://tippycoco.com/ 76 | - **Category:** Gaming/Open Source 77 | 78 | ### Item 19: Distributed Continuous GPU Profiling 79 | - **Link:** https://www.zymtrace.com/article/zero-friction-gpu-profiler 80 | - **Category:** Development Tools/Performance 81 | 82 | ### Item 20: A visual feast of galaxies, from infrared to X-ray 83 | - **Link:** https://www.esa.int/ESA_Multimedia/Images/2025/04/A_visual_feast_of_galaxies_from_infrared_to_X-ray 84 | - **Category:** Astronomy/Space 85 | 86 | ### Item 21: Minimal Linux Bootloader 87 | - **Link:** https://raw.githubusercontent.com/Stefan20162016/linux-insides-code/master/bootloader.asm 88 | - **Category:** Operating Systems/Low-level Programming 89 | 90 | ### Item 22: Lilith and Modula-2 91 | - **Link:** https://astrobe.com/Modula2/ 92 | - **Category:** Programming Languages/Computer History 93 | 94 | ### Item 23: Legendary Bose Magic Carpet Suspension Is Finally Going Global 95 | - **Link:** https://www.thedrive.com/news/legendary-bose-magic-carpet-suspension-is-finally-going-global 96 | - **Category:** Automotive/Engineering 97 | 98 | ### Item 24: Nevermind, an album on major chords 99 | - **Link:** https://farina00.github.io/essays/nevermind/ 100 | - **Category:** Music/Analysis 101 | 102 | ### Item 25: Metagenomics test saves woman's sight after mystery infection 103 | - **Link:** https://www.bbc.co.uk/news/articles/czx45vze0vyo 104 | - **Category:** Healthcare/Biotechnology 105 | 106 | ### Item 26: Show HN: I taught AI to commentate Pong in real time 107 | - **Link:** https://github.com/pncnmnp/xpong 108 | - **Category:** AI/Gaming 109 | 110 | ### Item 27: Brian Eno's Theory of Democracy 111 | - **Link:** https://www.programmablemutter.com/p/brian-enos-theory-of-democracy 112 | - **Category:** Politics/Philosophy 113 | 114 | ### Item 28: Pascal for Small Machines 115 | - **Link:** http://pascal.hansotten.com/ 116 | - **Category:** Programming Languages/Retrocomputing 117 | 118 | ### Item 29: When flat rate movers won't answer your calls 119 | - **Link:** https://aphyr.com/posts/381-when-flat-rate-movers-wont-answer-your-calls 120 | - **Category:** Consumer Issues/Personal Experience 121 | 122 | ### Item 30: Why can't HTML alone do includes? 123 | - **Link:** https://frontendmasters.com/blog/seeking-an-answer-why-cant-html-alone-do-includes/ 124 | - **Category:** Web Development/Standards 125 | 126 | --- 127 | 128 | ## Summary and Top Trends 129 | 130 | ### Key Statistics 131 | - **Total Items Processed:** 30 132 | - **Sources Covered:** 30 unique sources 133 | - **Categories Identified:** Programming/Development, AI/Machine Learning, Healthcare/Medical Technology, Open Source Projects, Hardware/Engineering, Web Tools, Computer History 134 | 135 | ### Top 3 Emerging Trends 136 | 137 | 1. **AI and Machine Learning Tools** 138 | - Frequency: 5 items related to this trend 139 | - Key development: Democratization of AI tools for consumer hardware and practical applications 140 | - Representative examples: Items 2, 8, 9, 14, 26 141 | 142 | 2. **Programming Language History and Evolution** 143 | - Frequency: 4 items related to this trend 144 | - Key development: Renewed interest in historical programming languages and systems 145 | - Representative examples: Items 10, 22, 28, 3 146 | 147 | 3. **Open Source Developer Tools and Frameworks** 148 | - Frequency: 6 items related to this trend 149 | - Key development: Community-driven solutions for common development challenges 150 | - Representative examples: Items 6, 12, 13, 15, 17, 19 151 | 152 | ### Notable Outliers 153 | - Item 23: Bose's suspension technology finally reaching global markets represents a significant advancement in automotive engineering after years of development 154 | - Item 25: Metagenomics test application in healthcare demonstrates cutting-edge biotechnology solving previously untreatable conditions 155 | - Item 7: EEG monitoring for anesthesia optimization shows intersection of neuroscience and practical medical applications 156 | 157 | ### Summary Insight 158 | The current technology landscape shows strong momentum in democratizing advanced tools, particularly in AI and machine learning, with projects like TScale enabling distributed training on consumer hardware. There's also a notable resurgence of interest in programming language history and foundational computer science concepts, suggesting a desire to revisit first principles. Healthcare technology continues to advance with practical applications of cutting-edge research, demonstrating technology's real-world impact beyond purely digital domains. 159 | -------------------------------------------------------------------------------- /summaries/main-summary.md: -------------------------------------------------------------------------------- 1 | # News for May 4, 2025 2 | 3 | ## Executive Overview 4 | 5 | ### Global Statistics 6 | - **Total Items Across All Sources:** 124 7 | - **Sources Processed:** 6 (Hacker News, WSJ Tech, WSJ Markets, TechCrunch, AI News, Wired) 8 | - **Date Range Covered:** May 2-4, 2025 9 | - **Total Categories Identified:** 42 10 | 11 | ### Category Distribution 12 | | Category | Count | Percentage | Top Source | 13 | |----------|-------|------------|------------| 14 | | AI/Machine Learning | 31 | 25% | AI News | 15 | | Business/Finance | 18 | 14.5% | WSJ Markets | 16 | | Technology | 16 | 12.9% | Hacker News | 17 | | Politics/Government | 7 | 5.6% | Wired | 18 | | Cybersecurity/Privacy | 6 | 4.8% | TechCrunch | 19 | | Trade Policy | 6 | 4.8% | WSJ Markets | 20 | 21 | --- 22 | 23 | ## Cross-Source Trends 24 | 25 | ### Global Top 5 Topics 26 | 27 | 1. **AI Integration Across Industries** 28 | - Mentions across sources: 31 29 | - Key sources: AI News, WSJ Tech, TechCrunch, Wired 30 | - Representative headlines: "AI Agents Are Learning How to Collaborate. Companies Need to Work With Them", "Agent-to-Agent (A2A) Collaboration", "Nvidia CEO Says All Companies Will Need 'AI Factories'" 31 | 32 | 2. **Trade Policy and Tariff Impact** 33 | - Mentions across sources: 12 34 | - Key sources: WSJ Markets, TechCrunch, WSJ Tech 35 | - Representative headlines: "Temu stops shipping products from China to the U.S.", "Car Buyers Rushing to Beat Tariffs Find It's Tougher to Get Financing", "The Future of Gadgets: Fewer Updates, More Subscriptions, Bigger Price Tags" 36 | 37 | 3. **Government AI Implementation** 38 | - Mentions across sources: 7 39 | - Key sources: Wired, AI News 40 | - Representative headlines: "DOGE Is in Its AI Era", "DOGE Put a College Student in Charge of Using AI to Rewrite Regulations", "A DOGE Recruiter Is Staffing a Project to Deploy AI Agents Across the US Government" 41 | 42 | 4. **AI Safety and Regulation Concerns** 43 | - Mentions across sources: 9 44 | - Key sources: TechCrunch, WSJ Tech, Wired 45 | - Representative headlines: "One of Google's recent Gemini AI models scores worse on safety", "AI chatbots are 'juicing engagement' instead of being useful", "Dozens of YouTube Channels Are Showing AI-Generated Cartoon Gore and Fetish Content" 46 | 47 | 5. **Autonomous Vehicles and Robotics** 48 | - Mentions across sources: 5 49 | - Key sources: TechCrunch, Wired 50 | - Representative headlines: "Aurora launches its driverless commercial trucking service", "Uber's latest autonomous vehicle partner? Chinese startup Momenta", "2025 Is the Year of the Humanoid Robot Factory Worker" 51 | 52 | ### Source-Specific Highlights 53 | 54 | - **Hacker News:** Strong focus on practical developer tools and open-source projects, with particular interest in AI democratization and programming language history 55 | - **WSJ Tech:** Emphasis on AI business applications and regulatory challenges facing tech giants 56 | - **WSJ Markets:** Concentrated coverage of trade tensions and their economic impact across sectors 57 | - **TechCrunch:** Balanced reporting on AI developments, autonomous vehicles, and trade policy effects on tech companies 58 | - **AI News:** Technical focus on model releases, agent capabilities, and industry-specific AI applications 59 | - **Wired:** Critical examination of government AI implementation and ethical concerns around AI content 60 | 61 | --- 62 | 63 | ## Categories by Source 64 | 65 | ### Hacker News - 30 Items 66 | - Programming/Development: 10 items 67 | - AI/Machine Learning: 5 items 68 | - Open Source Projects: 6 items 69 | - Healthcare/Medical Technology: 2 items 70 | - Hardware/Engineering: 4 items 71 | - Astronomy/Space: 1 item 72 | - Music/Analysis: 1 item 73 | - Consumer Issues: 1 item 74 | 75 | ### WSJ Tech - 20 Items 76 | - AI/Machine Learning: 8 items 77 | - Biotech: 4 items 78 | - Legal/Regulation: 3 items 79 | - Consumer Technology: 2 items 80 | - Privacy/Security: 2 items 81 | - Employment: 1 item 82 | 83 | ### WSJ Markets - 30 Items 84 | - Trade Policy: 6 items 85 | - Stock Market: 4 items 86 | - Banking/Finance: 5 items 87 | - Investment Strategy: 5 items 88 | - Auto Industry: 2 items 89 | - Commodities/Energy: 4 items 90 | - Real Estate: 1 item 91 | - Defense Industry: 1 item 92 | - Cryptocurrency: 1 item 93 | - ESG: 1 item 94 | 95 | ### TechCrunch - 20 Items 96 | - AI/Machine Learning: 6 items 97 | - E-commerce/Trade Policy: 3 items 98 | - Autonomous Vehicles: 2 items 99 | - Cybersecurity/Privacy: 2 items 100 | - Gaming: 2 items 101 | - Space Industry: 1 item 102 | - Enterprise Software: 1 item 103 | - Climate Tech: 1 item 104 | - Venture Capital: 1 item 105 | - Business/Investment: 1 item 106 | 107 | ### AI News - 34 Items 108 | - Model Releases/Updates: 8 items 109 | - AI Agents: 6 items 110 | - AI Applications: 5 items 111 | - AI Tools: 3 items 112 | - Model Evaluation: 3 items 113 | - Community Reactions: 5 items 114 | - AI UX/UI: 2 items 115 | - AI Funding: 1 item 116 | - AI Impact: 1 item 117 | 118 | ### Wired - 10 Items 119 | - Politics/Government AI: 3 items 120 | - AI Content Moderation: 1 item 121 | - AI for Sustainability: 1 item 122 | - AI Business/Corporate: 1 item 123 | - AI Legal/Copyright: 1 item 124 | - AI Privacy: 1 item 125 | - AI Robotics: 1 item 126 | - AI Security: 1 item 127 | 128 | --- 129 | 130 | ## Notable Cross-Source Stories 131 | 132 | ### Breaking Stories (Covered by 3+ sources) 133 | 1. Warren Buffett stepping down as Berkshire Hathaway CEO - Covered by: WSJ Markets, TechCrunch, WSJ Tech 134 | 2. SpaceX's Starbase incorporating as a city - Covered by: TechCrunch, WSJ Tech, Hacker News (indirectly) 135 | 3. Trade tensions and tariff impacts on technology supply chains - Covered by: WSJ Markets, WSJ Tech, TechCrunch 136 | 137 | ### Contradictory Perspectives 138 | - **Topic:** AI Safety and Regulation 139 | - TechCrunch perspective: Critical of AI companies prioritizing engagement over safety 140 | - AI News perspective: Focused on technical improvements and benchmarks 141 | - Wired perspective: Alarmed about government implementation without adequate oversight 142 | 143 | --- 144 | 145 | ## Strategic Insights 146 | 147 | ### Key Information Gaps 148 | - Detailed technical analysis of AI model capabilities beyond benchmarks 149 | - International perspectives outside of US-China trade tensions 150 | - Long-term economic impacts of AI integration across industries 151 | - Consumer sentiment regarding AI product adoption 152 | 153 | ### Emerging Opportunities 154 | - AI tools for climate resilience and supply chain optimization 155 | - Specialized AI applications in healthcare and biotech 156 | - Developer tools for AI integration and agent collaboration 157 | - Quantized and efficient AI models for edge deployment 158 | 159 | ### Master Summary 160 | The early May 2025 news cycle reveals an AI industry rapidly maturing beyond research into practical applications across government, business, and consumer sectors, while simultaneously facing growing concerns about safety, regulation, and ethical implementation. Trade tensions between the US and China are significantly impacting technology supply chains and business strategies, with companies like Temu halting US shipments and others absorbing tariff costs. Meanwhile, autonomous systems are moving from testing to commercial deployment in transportation and manufacturing, signaling a new phase of AI's physical-world impact. The contrast between AI News' technical optimism and Wired's critical examination of government AI implementation highlights the growing divide between AI capabilities and responsible governance frameworks. 161 | -------------------------------------------------------------------------------- /summaries/techcrunch-summary.md: -------------------------------------------------------------------------------- 1 | # TechCrunch Feed 2 | Date: May 4, 2025 3 | 4 | ## Complete Item List 5 | 6 | ### Item 1: Residents of SpaceX's Starbase launch site vote to incorporate as a city 7 | - **Link:** https://techcrunch.com/2025/05/04/residents-of-spacexs-starbase-launch-site-vote-to-incorporate-as-a-city/ 8 | - **Category:** Space/Corporate Towns 9 | 10 | ### Item 2: Revelo's LatAm talent network sees strong demand from US companies, thanks to AI 11 | - **Link:** https://techcrunch.com/2025/05/04/revelos-latam-talent-network-sees-strong-demand-from-us-companies-thanks-to-ai/ 12 | - **Category:** AI/Remote Work 13 | 14 | ### Item 3: Backstage access: Spotify's dev tools side-hustle is growing legs 15 | - **Link:** https://techcrunch.com/2025/05/04/backstage-access-spotifys-dev-tools-side-hustle-is-growing-legs/ 16 | - **Category:** Enterprise Software/Open Source 17 | 18 | ### Item 4: Temu stops shipping products from China to the U.S. 19 | - **Link:** https://techcrunch.com/2025/05/03/temu-stops-shipping-products-from-china-to-the-u-s/ 20 | - **Category:** E-commerce/Trade Policy 21 | 22 | ### Item 5: Warren Buffett will step down as Berkshire Hathaway CEO 23 | - **Link:** https://techcrunch.com/2025/05/03/warren-buffett-will-step-down-as-berkshire-hathaway-ceo/ 24 | - **Category:** Business/Investment 25 | 26 | ### Item 6: Week in Review: Apple won't raise prices — yet 27 | - **Link:** https://techcrunch.com/2025/05/03/week-in-review-apple-wont-raise-prices-yet/ 28 | - **Category:** Tech Industry/Tariffs 29 | 30 | ### Item 7: Google's Gemini has beaten Pokémon Blue (with a little help) 31 | - **Link:** https://techcrunch.com/2025/05/03/googles-gemini-has-beaten-pokemon-blue-with-a-little-help/ 32 | - **Category:** AI/Gaming 33 | 34 | ### Item 8: eBay and Etsy are relatively confident despite tariff pressures 35 | - **Link:** https://techcrunch.com/2025/05/03/ebay-and-etsy-are-relatively-confident-despite-tariff-pressures/ 36 | - **Category:** E-commerce/Tariffs 37 | 38 | ### Item 9: How Riot Games is fighting the war against video game hackers 39 | - **Link:** https://techcrunch.com/2025/05/03/how-riot-games-is-fighting-the-war-against-video-game-hackers/ 40 | - **Category:** Gaming/Cybersecurity 41 | 42 | ### Item 10: AI chatbots are 'juicing engagement' instead of being useful, Instagram co-founder warns 43 | - **Link:** https://techcrunch.com/2025/05/02/ai-chatbots-are-juicing-engagement-instead-of-being-useful-instagram-co-founder-warns/ 44 | - **Category:** AI/Product Design 45 | 46 | ### Item 11: TechCrunch Mobility: Aurora launches its driverless commercial trucking service, and a surprise bidder joins Canoo's bankruptcy case 47 | - **Link:** https://techcrunch.com/2025/05/02/techcrunch-mobility-aurora-launches-its-driverless-commercial-trucking-service-and-a-surprise-bidder-joins-canoos-bankruptcy-case/ 48 | - **Category:** Autonomous Vehicles/Transportation 49 | 50 | ### Item 12: Google will soon start letting kids under 13 use its Gemini chatbot 51 | - **Link:** https://techcrunch.com/2025/05/02/google-will-soon-start-letting-kids-under-13-use-its-gemini-chatbot/ 52 | - **Category:** AI/Child Safety 53 | 54 | ### Item 13: One of Google's recent Gemini AI models scores worse on safety 55 | - **Link:** https://techcrunch.com/2025/05/02/one-of-googles-recent-gemini-ai-models-scores-worse-on-safety/ 56 | - **Category:** AI/Safety 57 | 58 | ### Item 14: Apple and Anthropic reportedly partner to build an AI coding platform 59 | - **Link:** https://techcrunch.com/2025/05/02/apple-and-anthropic-reportedly-partner-to-build-an-ai-coding-platform/ 60 | - **Category:** AI/Developer Tools 61 | 62 | ### Item 15: Uber's latest autonomous vehicle partner? Chinese startup Momenta 63 | - **Link:** https://techcrunch.com/2025/05/02/ubers-latest-autonomous-vehicle-partner-chinese-startup-momenta/ 64 | - **Category:** Autonomous Vehicles/Partnerships 65 | 66 | ### Item 16: Dating app Raw exposed users' location data and personal information 67 | - **Link:** https://techcrunch.com/2025/05/02/dating-app-raw-exposed-users-location-data-personal-information/ 68 | - **Category:** Cybersecurity/Privacy 69 | 70 | ### Item 17: Startups Weekly: Drama or game-changer? You decide 71 | - **Link:** https://techcrunch.com/2025/05/02/startups-weekly-drama-or-game-changer-you-decide/ 72 | - **Category:** Startups/Venture Capital 73 | 74 | ### Item 18: Ara Partners' new $800M fund will decarbonize old industrial assets 75 | - **Link:** https://techcrunch.com/2025/05/02/ara-partners-new-800m-fund-will-decarbonize-old-industrial-assets/ 76 | - **Category:** Climate Tech/Venture Capital 77 | 78 | ### Item 19: OpenAI pledges to make changes to prevent future ChatGPT sycophancy 79 | - **Link:** https://techcrunch.com/2025/05/02/openai-pledges-to-make-changes-to-prevent-future-chatgpt-sycophancy/ 80 | - **Category:** AI/Product Updates 81 | 82 | ### Item 20: Google's NotebookLM Android and iOS apps are available for preorder 83 | - **Link:** https://techcrunch.com/2025/05/02/googles-notebooklm-android-and-ios-apps-are-available-for-pre-order/ 84 | - **Category:** AI/Productivity Apps 85 | 86 | --- 87 | 88 | ## Summary and Top Trends 89 | 90 | ### Key Statistics 91 | - **Total Items Processed:** 20 92 | - **Sources Covered:** 1 (TechCrunch) 93 | - **Categories Identified:** 12 (AI, E-commerce, Gaming, Autonomous Vehicles, Cybersecurity, Space, Enterprise Software, Business, Climate Tech, Venture Capital, Privacy, Productivity) 94 | 95 | ### Top 3 Emerging Trends 96 | 97 | 1. **AI Safety and User Experience Concerns** 98 | - Frequency: 6 items related to this trend 99 | - Key development: Growing criticism of AI systems prioritizing engagement over utility, alongside safety regressions in newer models 100 | - Representative examples: Items 10, 12, 13, 19 101 | 102 | 2. **Trade Policy Impact on Tech Companies** 103 | - Frequency: 3 items related to this trend 104 | - Key development: Companies adapting to new tariffs, with Chinese e-commerce platform Temu halting US shipments and Apple absorbing $900M in tariff costs 105 | - Representative examples: Items 4, 6, 8 106 | 107 | 3. **Autonomous Vehicle Industry Acceleration** 108 | - Frequency: 2 items related to this trend 109 | - Key development: Uber expanding autonomous partnerships while Aurora launches commercial driverless trucking 110 | - Representative examples: Items 11, 15 111 | 112 | ### Notable Outliers 113 | - SpaceX's Starbase becoming an official city through resident vote (Item 1) 114 | - Warren Buffett announcing his retirement as Berkshire Hathaway CEO (Item 5) 115 | - Dating app Raw exposing sensitive user location data despite encryption claims (Item 16) 116 | 117 | ### Summary Insight 118 | The tech industry is navigating significant challenges around AI safety and responsible deployment, with prominent figures like Instagram's co-founder criticizing engagement-focused design patterns. Meanwhile, companies are adapting to new trade policies that particularly impact US-China commerce relationships. The autonomous vehicle sector shows signs of commercial maturity with Aurora's driverless trucking launch and Uber's expanding partnership strategy, indicating the technology is moving beyond testing into real-world implementation. 119 | -------------------------------------------------------------------------------- /summaries/wired-summary.md: -------------------------------------------------------------------------------- 1 | # Wired AI Feed 2 | Date: 2025-05-04 3 | 4 | ## Complete Item List 5 | 6 | ### Item 1: DOGE Is in Its AI Era 7 | - **Link:** https://www.wired.com/story/doge-is-in-its-ai-era/ 8 | - **Category:** Politics/Government AI 9 | 10 | ### Item 2: A DOGE Recruiter Is Staffing a Project to Deploy AI Agents Across the US Government 11 | - **Link:** https://www.wired.com/story/doge-recruiter-ai-agents-palantir-clown-emoji/ 12 | - **Category:** Politics/Government AI 13 | 14 | ### Item 3: Dozens of YouTube Channels Are Showing AI-Generated Cartoon Gore and Fetish Content 15 | - **Link:** https://www.wired.com/story/dozens-of-youtube-channels-are-showing-ai-generated-cartoon-gore-and-fetish-content/ 16 | - **Category:** AI Content Moderation 17 | 18 | ### Item 4: The Climate Crisis Threatens Supply Chains. Manufacturers Hope AI Can Help 19 | - **Link:** https://www.wired.com/story/manufacturers-hope-ai-will-save-supply-chains-from-climate-crisis/ 20 | - **Category:** AI for Sustainability 21 | 22 | ### Item 5: Inside the Battle Over OpenAI's Corporate Restructuring 23 | - **Link:** https://www.wired.com/story/open-ai-nonprofit-transition-activism/ 24 | - **Category:** AI Business/Corporate 25 | 26 | ### Item 6: A Judge Says Meta's AI Copyright Case Is About 'the Next Taylor Swift' 27 | - **Link:** https://www.wired.com/story/meta-lawsuit-copyright-hearing-artificial-intelligence/ 28 | - **Category:** AI Legal/Copyright 29 | 30 | ### Item 7: Think Twice Before Creating That ChatGPT Action Figure 31 | - **Link:** https://www.wired.com/story/chatgpt-image-generator-action-figure-privacy/ 32 | - **Category:** AI Privacy 33 | 34 | ### Item 8: 2025 Is the Year of the Humanoid Robot Factory Worker 35 | - **Link:** https://www.wired.com/story/2025-year-of-the-humanoid-robot-factory-worker/ 36 | - **Category:** AI Robotics 37 | 38 | ### Item 9: North Korea Stole Your Job 39 | - **Link:** https://www.wired.com/story/north-korea-stole-your-tech-job-ai-interviews/ 40 | - **Category:** AI Security 41 | 42 | ### Item 10: DOGE Put a College Student in Charge of Using AI to Rewrite Regulations 43 | - **Link:** https://www.wired.com/story/doge-college-student-ai-rewrite-regulations-deregulation/ 44 | - **Category:** Politics/Government AI 45 | 46 | --- 47 | 48 | ## Summary and Top Trends 49 | 50 | ### Key Statistics 51 | - **Total Items Processed:** 10 52 | - **Sources Covered:** 1 (Wired) 53 | - **Categories Identified:** Politics/Government AI, AI Content Moderation, AI for Sustainability, AI Business/Corporate, AI Legal/Copyright, AI Privacy, AI Robotics, AI Security 54 | 55 | ### Top 3 Emerging Trends 56 | 57 | 1. **Government AI Implementation and Regulation** 58 | - Frequency: 3 items related to this trend 59 | - Key development: DOGE administration's aggressive and potentially concerning implementation of AI across government functions 60 | - Representative examples: Items 1, 2, 10 61 | 62 | 2. **AI Legal and Ethical Challenges** 63 | - Frequency: 3 items related to this trend 64 | - Key development: Ongoing legal battles over copyright, content moderation issues with AI-generated inappropriate content, and privacy concerns 65 | - Representative examples: Items 3, 6, 7 66 | 67 | 3. **AI in Physical World Applications** 68 | - Frequency: 2 items related to this trend 69 | - Key development: Humanoid robots entering manufacturing and AI being applied to supply chain resilience against climate change 70 | - Representative examples: Items 4, 8 71 | 72 | ### Notable Outliers 73 | - North Korea's use of AI to facilitate tech job infiltration represents a concerning evolution of nation-state cyber operations 74 | - OpenAI's corporate restructuring battle highlights the ongoing tension between profit motives and responsible AI development 75 | 76 | ### Summary Insight 77 | Wired's coverage reveals a concerning trend of hasty AI implementation in government sectors without adequate oversight, alongside growing legal and ethical challenges in content moderation and copyright. Meanwhile, AI's physical-world applications are maturing in manufacturing and supply chain management, suggesting we're at an inflection point where AI is moving beyond digital-only applications into systems with real-world consequences. 78 | -------------------------------------------------------------------------------- /summaries/wsj-markets-summary.md: -------------------------------------------------------------------------------- 1 | # WSJ Markets Feed 2 | Date: May 4, 2025 3 | 4 | ## Complete Item List 5 | 6 | ### Item 1: Warren Buffett, on Stage at Berkshire Meeting, Defends Global Trade 7 | - **Link:** https://www.wsj.com/finance/stocks/berkshire-hathaway-annual-meeting-2025-89f836c4?mod=rss_markets_main 8 | - **Category:** Investment/Trade Policy 9 | 10 | ### Item 2: Harvard's Brawl With Trump Casts Doubt on Its Pristine Credit 11 | - **Link:** https://www.wsj.com/finance/investing/harvards-brawl-with-trump-casts-doubt-on-its-pristine-credit-4c274e43?mod=rss_markets_main 12 | - **Category:** Education Finance/Politics 13 | 14 | ### Item 3: What Happened in Two Days at a Very Wild Crypto Party 15 | - **Link:** https://www.wsj.com/finance/crypto-token2049-dubai-cz-eric-trump-rave-093b1d7e?mod=rss_markets_main 16 | - **Category:** Cryptocurrency 17 | 18 | ### Item 4: What the World's Biggest Investor Is Doing About Trump's Tariffs 19 | - **Link:** https://www.wsj.com/finance/investing/what-the-worlds-biggest-investor-is-doing-about-trumps-tariffs-51bc7adc?mod=rss_markets_main 20 | - **Category:** Investment/Trade Policy 21 | 22 | ### Item 5: Hopes on Trade, Economy Drive Week of Stock Gains 23 | - **Link:** https://www.wsj.com/finance/stocks/hopes-on-trade-economy-drive-week-of-stock-gains-c36e902b?mod=rss_markets_main 24 | - **Category:** Stock Market 25 | 26 | ### Item 6: Car Buyers Rushing to Beat Tariffs Find It's Tougher to Get Financing 27 | - **Link:** https://www.wsj.com/personal-finance/auto-tariffs-car-buyers-loans-financing-dab6499a?mod=rss_markets_main 28 | - **Category:** Auto Industry/Consumer Finance 29 | 30 | ### Item 7: What Big Tech Has Going for It in the Trade War 31 | - **Link:** https://www.wsj.com/finance/what-big-tech-has-going-for-it-in-the-trade-war-41174fa0?mod=rss_markets_main 32 | - **Category:** Technology/Trade Policy 33 | 34 | ### Item 8: Europe Is Racing to Build Its Own Version of the U.S. Military-Industrial Complex 35 | - **Link:** https://www.wsj.com/finance/europe-defense-us-military-industrial-complex-61ea9654?mod=rss_markets_main 36 | - **Category:** Defense Industry/European Markets 37 | 38 | ### Item 9: Home Builders Are Piling on Discounts as They Struggle to Entice Buyers 39 | - **Link:** https://www.wsj.com/economy/housing/home-builders-are-piling-on-discounts-as-they-struggle-to-entice-buyers-cf2cf236?mod=rss_markets_main 40 | - **Category:** Real Estate/Housing Market 41 | 42 | ### Item 10: Chrysler-Owner Stellantis Hopes for Eventual Gains From Tariffs, but Investors Disagree 43 | - **Link:** https://www.wsj.com/business/autos/chrysler-owner-stellantis-hopes-for-eventual-gains-from-tariffs-but-investors-disagree-66b2c77a?mod=rss_markets_main 44 | - **Category:** Auto Industry/Trade Policy 45 | 46 | ### Item 11: Why New Wegovy Deals Won't Restore Novo Nordisk's Obesity Lead 47 | - **Link:** https://www.wsj.com/health/pharma/novo-nordisk-ozempic-eli-lilly-c7ac45ae?mod=rss_markets_main 48 | - **Category:** Pharmaceutical Industry 49 | 50 | ### Item 12: Financial Services Roundup: Market Talk 51 | - **Link:** https://www.wsj.com/finance/banking/financial-services-roundup-market-talk-bb0a7eb8?mod=rss_markets_main 52 | - **Category:** Financial Services 53 | 54 | ### Item 13: Shareholders Call on HSBC to Reaffirm Net-Zero Pledge 55 | - **Link:** https://www.wsj.com/finance/banking/shareholders-call-on-hsbc-to-reaffirm-net-zero-pledge-3935d53d?mod=rss_markets_main 56 | - **Category:** Banking/ESG 57 | 58 | ### Item 14: Goldman Sachs Removes Mentions of 'Black' From Flagship Diversity Pledge 59 | - **Link:** https://www.wsj.com/finance/banking/goldman-sachs-removes-mentions-of-black-from-flagship-diversity-pledge-3110861e?mod=rss_markets_main 60 | - **Category:** Banking/Corporate Policy 61 | 62 | ### Item 15: Standard Chartered Posts Profit Growth, Maintains Guidance 63 | - **Link:** https://www.wsj.com/finance/banking/standard-chartereds-quarterly-profit-rises-maintains-guidance-c9a5e086?mod=rss_markets_main 64 | - **Category:** Banking/Earnings 65 | 66 | ### Item 16: Financial Services Roundup: Market Talk 67 | - **Link:** https://www.wsj.com/finance/banking/financial-services-roundup-market-talk-5cd33478?mod=rss_markets_main 68 | - **Category:** Financial Services 69 | 70 | ### Item 17: These Dividend Stocks Could Insulate Your Portfolio From Tariffs, Recession 71 | - **Link:** https://www.wsj.com/finance/stocks/dividend-stocks-midcap-recession-protection-e6f33c2d?mod=rss_markets_main 72 | - **Category:** Stock Market/Investment Strategy 73 | 74 | ### Item 18: The Score: Meta Platforms, McDonald's, Kohl's and More Stocks That Defined the Week 75 | - **Link:** https://www.wsj.com/finance/stocks/the-score-meta-platforms-mcdonalds-kohls-and-more-stocks-that-defined-the-week-9a58f04a?mod=rss_markets_main 76 | - **Category:** Stock Market 77 | 78 | ### Item 19: Global Markets Boosted by Strong U.S. Tech Earnings, Easing Trade Tension Hopes 79 | - **Link:** https://www.wsj.com/finance/stocks/global-markets-boosted-by-strong-u-s-tech-earnings-easing-trade-tension-hopes-2831b747?mod=rss_markets_main 80 | - **Category:** Global Markets/Tech Stocks 81 | 82 | ### Item 20: Asia Markets Rise on U.S. Tech Earnings, Signs of Easing U.S.-China Tensions 83 | - **Link:** https://www.wsj.com/finance/stocks/asia-markets-rise-on-u-s-tech-earnings-signs-of-easing-u-s-china-tensions-c538d6ed?mod=rss_markets_main 84 | - **Category:** Asian Markets/Trade Relations 85 | 86 | ### Item 21: Tech Rally Sends S&P 500 Higher for Eighth Straight Session 87 | - **Link:** https://www.wsj.com/finance/stocks/tech-rally-sends-s-p-500-higher-for-eighth-straight-session-83b11899?mod=rss_markets_main 88 | - **Category:** Stock Market/Tech Stocks 89 | 90 | ### Item 22: Stock Funds Showed Some Fight in April 91 | - **Link:** https://www.wsj.com/finance/investing/stock-funds-showed-fight-april-0a372e52?mod=rss_markets_main 92 | - **Category:** Investment Funds 93 | 94 | ### Item 23: Why There Will Never Be Another Warren Buffett 95 | - **Link:** https://www.wsj.com/finance/investing/why-there-will-never-be-another-warren-buffett-2b5fa268?mod=rss_markets_main 96 | - **Category:** Investment/Profile 97 | 98 | ### Item 24: The Lesson in Buffett's Winning Apple Bet 99 | - **Link:** https://www.wsj.com/finance/investing/the-lesson-in-buffetts-winning-apple-bet-bac56de3?mod=rss_markets_main 100 | - **Category:** Investment Strategy 101 | 102 | ### Item 25: Read the WSJ's Early Coverage of Warren Buffett 103 | - **Link:** https://www.wsj.com/finance/investing/read-the-wsjs-early-coverage-of-warren-buffett-01b09b9c?mod=rss_markets_main 104 | - **Category:** Investment/Historical 105 | 106 | ### Item 26: Guess How Much Time Many Investors Spend on Researching Stock Buys? 107 | - **Link:** https://www.wsj.com/finance/investing/buying-stocks-research-study-2a839a4a?mod=rss_markets_main 108 | - **Category:** Investment Behavior 109 | 110 | ### Item 27: Oil Futures Fall Ahead of OPEC+ Meeting 111 | - **Link:** https://www.wsj.com/finance/commodities-futures/oil-edges-lower-amid-supply-concerns-ahead-of-next-weeks-opec-meeting-ac73133b?mod=rss_markets_main 112 | - **Category:** Commodities/Energy 113 | 114 | ### Item 28: U.S. Natural Gas Snaps Four-Week Losing Streak 115 | - **Link:** https://www.wsj.com/finance/commodities-futures/u-s-natural-gas-futures-add-to-gains-ed3bac19?mod=rss_markets_main 116 | - **Category:** Commodities/Energy 117 | 118 | ### Item 29: Gold Mounts Comeback to End Week 119 | - **Link:** https://www.wsj.com/finance/commodities-futures/gold-consolidates-fundamentals-solid-despite-recent-selloff-32178698?mod=rss_markets_main 120 | - **Category:** Commodities/Precious Metals 121 | 122 | ### Item 30: U.S. Natural Gas Futures Resume Rally 123 | - **Link:** https://www.wsj.com/finance/commodities-futures/u-s-natural-gas-futures-pick-up-ahead-of-storage-data-28be3959?mod=rss_markets_main 124 | - **Category:** Commodities/Energy 125 | 126 | --- 127 | 128 | ## Summary and Top Trends 129 | 130 | ### Key Statistics 131 | - **Total Items Processed:** 30 132 | - **Sources Covered:** 1 (Wall Street Journal) 133 | - **Categories Identified:** 15 (Trade Policy, Stock Market, Banking, Investment, Commodities, Auto Industry, Technology, Real Estate, Pharmaceutical, Financial Services, ESG, Defense Industry, Cryptocurrency, Education Finance, Consumer Finance) 134 | 135 | ### Top 3 Emerging Trends 136 | 137 | 1. **Trade Tensions and Tariff Impact** 138 | - Frequency: 8 items related to this trend 139 | - Key development: Widespread market concern about Trump administration tariffs affecting various sectors 140 | - Representative examples: Items 1, 4, 6, 7, 10, 15, 17, 20 141 | 142 | 2. **Warren Buffett and Berkshire Hathaway Focus** 143 | - Frequency: 4 items related to this trend 144 | - Key development: Coverage of Berkshire Hathaway annual meeting and Buffett's investment legacy 145 | - Representative examples: Items 1, 23, 24, 25 146 | 147 | 3. **Tech Sector Resilience** 148 | - Frequency: 5 items related to this trend 149 | - Key development: Strong tech earnings driving market gains despite trade concerns 150 | - Representative examples: Items 7, 19, 20, 21, 24 151 | 152 | ### Notable Outliers 153 | - Cryptocurrency party in Dubai featuring high-profile attendees (Item 3) 154 | - Goldman Sachs changing diversity language in corporate pledges (Item 14) 155 | - European defense industry expansion in response to geopolitical shifts (Item 8) 156 | 157 | ### Summary Insight 158 | The financial markets are currently navigating significant trade policy uncertainties while being buoyed by strong tech sector performance. Warren Buffett's annual meeting has drawn attention to both his investment legacy and his stance against using trade as a weapon. Meanwhile, various sectors are adapting differently to tariff threats, with some seeking protection strategies while others like tech showing resilience despite the challenging environment. 159 | -------------------------------------------------------------------------------- /summaries/wsj-tech-summary.md: -------------------------------------------------------------------------------- 1 | # Wall Street Journal - Tech 2 | Date: May 4, 2025 3 | 4 | ## Complete Item List 5 | 6 | ### Item 1: To Win Monopoly Fight, Meta Is Touting a Rival: TikTok 7 | - **Link:** https://www.wsj.com/tech/meta-antitrust-trial-tiktok-80b23087?mod=rss_Technology 8 | - **Category:** Legal/Regulation 9 | 10 | ### Item 2: Intimidated by AI? Here's How to Get Started 11 | - **Link:** https://www.wsj.com/tech/ai/using-ai-tips-prompts-chatbots-61d0964c?mod=rss_Technology 12 | - **Category:** AI/Consumer Technology 13 | 14 | ### Item 3: The MAHA-Friendly App That's Driving Food Companies Crazy 15 | - **Link:** https://www.wsj.com/tech/personal-tech/yuka-app-food-scanning-companies-a8d526b6?mod=rss_Technology 16 | - **Category:** Consumer Apps/Food Technology 17 | 18 | ### Item 4: Welcome to Starbase, Texas. What's Next for Elon Musk's Rocket-Building Company Town 19 | - **Link:** https://www.wsj.com/us-news/welcome-to-starbase-texas-whats-next-for-elon-musks-rocket-building-company-town-400cb53a?mod=rss_Technology 20 | - **Category:** Space Industry/Corporate Development 21 | 22 | ### Item 5: The Lesson in Buffett's Winning Apple Bet 23 | - **Link:** https://www.wsj.com/finance/investing/the-lesson-in-buffetts-winning-apple-bet-bac56de3?mod=rss_Technology 24 | - **Category:** Investing/Tech Companies 25 | 26 | ### Item 6: AI Agents Are Learning How to Collaborate. Companies Need to Work With Them 27 | - **Link:** https://www.wsj.com/articles/ai-agents-are-learning-how-to-collaborate-companies-need-to-work-with-them-28c7464d?mod=rss_Technology 28 | - **Category:** AI/Business Strategy 29 | 30 | ### Item 7: I Recorded Everything I Said for Three Months. AI Has Replaced My Memory 31 | - **Link:** https://www.wsj.com/tech/personal-tech/ai-personal-assistant-wearable-tech-impressions-28156b57?mod=rss_Technology 32 | - **Category:** AI/Wearable Technology 33 | 34 | ### Item 8: The Future of Gadgets: Fewer Updates, More Subscriptions, Bigger Price Tags 35 | - **Link:** https://www.wsj.com/tech/personal-tech/electronics-tariffs-china-price-shortages-53b3abb9?mod=rss_Technology 36 | - **Category:** Consumer Electronics/Business Models 37 | 38 | ### Item 9: So Long Skype, Thanks for All the Dropped Calls 39 | - **Link:** https://www.wsj.com/tech/personal-tech/so-long-skype-thanks-for-all-the-dropped-calls-ccc22f96?mod=rss_Technology 40 | - **Category:** Software/Tech History 41 | 42 | ### Item 10: Go Delete Yourself From the Internet. Seriously, Here's How 43 | - **Link:** https://www.wsj.com/tech/personal-tech/personal-information-privacy-deleteme-2ceea2ad?mod=rss_Technology 44 | - **Category:** Privacy/Digital Security 45 | 46 | ### Item 11: Nine Ways to Protect Yourself From 'Impostor' Voice Scams 47 | - **Link:** https://www.wsj.com/tech/personal-tech/ai-voice-imposter-scam-tips-99ce7164?mod=rss_Technology 48 | - **Category:** Cybersecurity/AI 49 | 50 | ### Item 12: IT Unemployment Ticked Down in April. But So Did the Size of the IT Job Market 51 | - **Link:** https://www.wsj.com/articles/it-unemployment-ticked-down-in-april-but-so-did-the-size-of-the-it-job-market-6efe0d3d?mod=rss_Technology 52 | - **Category:** Tech Employment/Economy 53 | 54 | ### Item 13: Nvidia CEO Says All Companies Will Need 'AI Factories,' Touts Creation of American Jobs 55 | - **Link:** https://www.wsj.com/articles/nvidia-ceo-says-all-companies-will-need-ai-factories-touts-creation-of-american-jobs-33e07998?mod=rss_Technology 56 | - **Category:** AI Infrastructure/Manufacturing 57 | 58 | ### Item 14: How AI Is Helping Job Seekers Pivot to New Careers 59 | - **Link:** https://www.wsj.com/tech/ai/ai-job-hunt-career-change-41f6bd4b?mod=rss_Technology 60 | - **Category:** AI/Employment 61 | 62 | ### Item 15: Meta Launches New Standalone AI App, Rivaling ChatGPT 63 | - **Link:** https://www.wsj.com/tech/ai/meta-launches-new-standalone-ai-app-rivaling-chatgpt-60c0d161?mod=rss_Technology 64 | - **Category:** AI/Tech Competition 65 | 66 | ### Item 16: Activist Robby Starbuck Sues Meta Over AI Answers About Him 67 | - **Link:** https://www.wsj.com/tech/ai/activist-robby-starbuck-sues-meta-over-ai-answers-about-him-9eba5d8a?mod=rss_Technology 68 | - **Category:** AI/Legal 69 | 70 | ### Item 17: How to Play the Biotech Meltdown in the Age of RFK Jr. and Tariffs 71 | - **Link:** https://www.wsj.com/tech/biotech/biotech-industry-trump-tariffs-rfk-jr-62a3cfc1?mod=rss_Technology 72 | - **Category:** Biotech/Investing 73 | 74 | ### Item 18: Market Volatility to Drive Closer Collaboration Between Biotech Startups, Large Pharma 75 | - **Link:** https://www.wsj.com/articles/market-volatility-to-drive-closer-collaboration-between-biotech-startups-large-pharma-473c0199?mod=rss_Technology 76 | - **Category:** Biotech/Business Strategy 77 | 78 | ### Item 19: China's Biotech Advances Threaten U.S. Dominance, Warns Congressional Report 79 | - **Link:** https://www.wsj.com/tech/biotech/china-biotech-industry-research-threat-e91dddd6?mod=rss_Technology 80 | - **Category:** Biotech/International Competition 81 | 82 | ### Item 20: 23andMe Went From a $6 Billion Giant to Bankruptcy. Its Former CEO Won't Walk Away 83 | - **Link:** https://www.wsj.com/tech/biotech/23andme-went-from-a-6-billion-giant-to-bankruptcy-its-former-ceo-wont-walk-away-8df3a9d4?mod=rss_Technology 84 | - **Category:** Biotech/Business Failure 85 | 86 | --- 87 | 88 | ## Summary and Top Trends 89 | 90 | ### Key Statistics 91 | - **Total Items Processed:** 20 92 | - **Sources Covered:** 1 (Wall Street Journal) 93 | - **Categories Identified:** AI/Machine Learning, Biotech, Consumer Technology, Business Strategy, Legal/Regulation, Privacy/Security, Employment 94 | 95 | ### Top 3 Emerging Trends 96 | 97 | 1. **AI Integration Across Industries** 98 | - Frequency: 8 items related to this trend 99 | - Key development: AI moving beyond experimental phase to practical implementation in business processes, personal tools, and job markets 100 | - Representative examples: Items 2, 6, 7, 11, 13, 14, 15, 16 101 | 102 | 2. **Biotech Industry Restructuring** 103 | - Frequency: 4 items related to this trend 104 | - Key development: Major shifts in biotech business models due to market pressures, international competition, and high-profile failures 105 | - Representative examples: Items 17, 18, 19, 20 106 | 107 | 3. **Tech Regulation and Legal Challenges** 108 | - Frequency: 3 items related to this trend 109 | - Key development: Increasing legal scrutiny of tech giants and AI applications, with implications for business models and consumer protection 110 | - Representative examples: Items 1, 10, 16 111 | 112 | ### Notable Outliers 113 | - Item 4: SpaceX's Starbase incorporation represents a unique development in corporate-municipal relationships 114 | - Item 9: Microsoft's final retirement of Skype marks the end of an era in communication technology 115 | - Item 7: The emergence of AI-powered memory augmentation through wearable technology signals a profound shift in human-computer interaction 116 | 117 | ### Summary Insight 118 | The technology landscape in 2025 is characterized by AI's rapid integration into everyday business and consumer applications, moving beyond novelty to necessity. Meanwhile, the biotech sector is undergoing significant restructuring amid financial pressures and geopolitical competition, with high-profile failures like 23andMe highlighting the risks. Tech regulation continues to evolve with increasing legal challenges to both established tech giants and emerging AI applications, suggesting a maturing regulatory environment for digital technologies. 119 | -------------------------------------------------------------------------------- /uv.lock: -------------------------------------------------------------------------------- 1 | version = 1 2 | requires-python = ">=3.12" 3 | 4 | [[package]] 5 | name = "annotated-types" 6 | version = "0.7.0" 7 | source = { registry = "https://pypi.org/simple" } 8 | sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } 9 | wheels = [ 10 | { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, 11 | ] 12 | 13 | [[package]] 14 | name = "anyio" 15 | version = "4.9.0" 16 | source = { registry = "https://pypi.org/simple" } 17 | dependencies = [ 18 | { name = "idna" }, 19 | { name = "sniffio" }, 20 | { name = "typing-extensions", marker = "python_full_version < '3.13'" }, 21 | ] 22 | sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949 } 23 | wheels = [ 24 | { url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916 }, 25 | ] 26 | 27 | [[package]] 28 | name = "certifi" 29 | version = "2025.4.26" 30 | source = { registry = "https://pypi.org/simple" } 31 | sdist = { url = "https://files.pythonhosted.org/packages/e8/9e/c05b3920a3b7d20d3d3310465f50348e5b3694f4f88c6daf736eef3024c4/certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6", size = 160705 } 32 | wheels = [ 33 | { url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3", size = 159618 }, 34 | ] 35 | 36 | [[package]] 37 | name = "click" 38 | version = "8.1.8" 39 | source = { registry = "https://pypi.org/simple" } 40 | dependencies = [ 41 | { name = "colorama", marker = "platform_system == 'Windows'" }, 42 | ] 43 | sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 } 44 | wheels = [ 45 | { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 }, 46 | ] 47 | 48 | [[package]] 49 | name = "colorama" 50 | version = "0.4.6" 51 | source = { registry = "https://pypi.org/simple" } 52 | sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } 53 | wheels = [ 54 | { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, 55 | ] 56 | 57 | [[package]] 58 | name = "h11" 59 | version = "0.16.0" 60 | source = { registry = "https://pypi.org/simple" } 61 | sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250 } 62 | wheels = [ 63 | { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515 }, 64 | ] 65 | 66 | [[package]] 67 | name = "httpcore" 68 | version = "1.0.9" 69 | source = { registry = "https://pypi.org/simple" } 70 | dependencies = [ 71 | { name = "certifi" }, 72 | { name = "h11" }, 73 | ] 74 | sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484 } 75 | wheels = [ 76 | { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784 }, 77 | ] 78 | 79 | [[package]] 80 | name = "httpx" 81 | version = "0.28.1" 82 | source = { registry = "https://pypi.org/simple" } 83 | dependencies = [ 84 | { name = "anyio" }, 85 | { name = "certifi" }, 86 | { name = "httpcore" }, 87 | { name = "idna" }, 88 | ] 89 | sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406 } 90 | wheels = [ 91 | { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 }, 92 | ] 93 | 94 | [[package]] 95 | name = "httpx-sse" 96 | version = "0.4.0" 97 | source = { registry = "https://pypi.org/simple" } 98 | sdist = { url = "https://files.pythonhosted.org/packages/4c/60/8f4281fa9bbf3c8034fd54c0e7412e66edbab6bc74c4996bd616f8d0406e/httpx-sse-0.4.0.tar.gz", hash = "sha256:1e81a3a3070ce322add1d3529ed42eb5f70817f45ed6ec915ab753f961139721", size = 12624 } 99 | wheels = [ 100 | { url = "https://files.pythonhosted.org/packages/e1/9b/a181f281f65d776426002f330c31849b86b31fc9d848db62e16f03ff739f/httpx_sse-0.4.0-py3-none-any.whl", hash = "sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f", size = 7819 }, 101 | ] 102 | 103 | [[package]] 104 | name = "idna" 105 | version = "3.10" 106 | source = { registry = "https://pypi.org/simple" } 107 | sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } 108 | wheels = [ 109 | { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, 110 | ] 111 | 112 | [[package]] 113 | name = "markdown-it-py" 114 | version = "3.0.0" 115 | source = { registry = "https://pypi.org/simple" } 116 | dependencies = [ 117 | { name = "mdurl" }, 118 | ] 119 | sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } 120 | wheels = [ 121 | { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, 122 | ] 123 | 124 | [[package]] 125 | name = "mcp" 126 | version = "1.7.1" 127 | source = { registry = "https://pypi.org/simple" } 128 | dependencies = [ 129 | { name = "anyio" }, 130 | { name = "httpx" }, 131 | { name = "httpx-sse" }, 132 | { name = "pydantic" }, 133 | { name = "pydantic-settings" }, 134 | { name = "python-multipart" }, 135 | { name = "sse-starlette" }, 136 | { name = "starlette" }, 137 | { name = "uvicorn", marker = "sys_platform != 'emscripten'" }, 138 | ] 139 | sdist = { url = "https://files.pythonhosted.org/packages/25/ae/588691c45b38f4fbac07fa3d6d50cea44cc6b35d16ddfdf26e17a0467ab2/mcp-1.7.1.tar.gz", hash = "sha256:eb4f1f53bd717f75dda8a1416e00804b831a8f3c331e23447a03b78f04b43a6e", size = 230903 } 140 | wheels = [ 141 | { url = "https://files.pythonhosted.org/packages/ae/79/fe0e20c3358997a80911af51bad927b5ea2f343ef95ab092b19c9cc48b59/mcp-1.7.1-py3-none-any.whl", hash = "sha256:f7e6108977db6d03418495426c7ace085ba2341b75197f8727f96f9cfd30057a", size = 100365 }, 142 | ] 143 | 144 | [package.optional-dependencies] 145 | cli = [ 146 | { name = "python-dotenv" }, 147 | { name = "typer" }, 148 | ] 149 | 150 | [[package]] 151 | name = "mdurl" 152 | version = "0.1.2" 153 | source = { registry = "https://pypi.org/simple" } 154 | sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } 155 | wheels = [ 156 | { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, 157 | ] 158 | 159 | [[package]] 160 | name = "news-agents" 161 | version = "0.1.0" 162 | source = { editable = "." } 163 | dependencies = [ 164 | { name = "httpx" }, 165 | { name = "mcp", extra = ["cli"] }, 166 | ] 167 | 168 | [package.metadata] 169 | requires-dist = [ 170 | { name = "httpx", specifier = ">=0.28.1" }, 171 | { name = "mcp", extras = ["cli"], specifier = ">=1.7.1" }, 172 | ] 173 | 174 | [[package]] 175 | name = "pydantic" 176 | version = "2.11.4" 177 | source = { registry = "https://pypi.org/simple" } 178 | dependencies = [ 179 | { name = "annotated-types" }, 180 | { name = "pydantic-core" }, 181 | { name = "typing-extensions" }, 182 | { name = "typing-inspection" }, 183 | ] 184 | sdist = { url = "https://files.pythonhosted.org/packages/77/ab/5250d56ad03884ab5efd07f734203943c8a8ab40d551e208af81d0257bf2/pydantic-2.11.4.tar.gz", hash = "sha256:32738d19d63a226a52eed76645a98ee07c1f410ee41d93b4afbfa85ed8111c2d", size = 786540 } 185 | wheels = [ 186 | { url = "https://files.pythonhosted.org/packages/e7/12/46b65f3534d099349e38ef6ec98b1a5a81f42536d17e0ba382c28c67ba67/pydantic-2.11.4-py3-none-any.whl", hash = "sha256:d9615eaa9ac5a063471da949c8fc16376a84afb5024688b3ff885693506764eb", size = 443900 }, 187 | ] 188 | 189 | [[package]] 190 | name = "pydantic-core" 191 | version = "2.33.2" 192 | source = { registry = "https://pypi.org/simple" } 193 | dependencies = [ 194 | { name = "typing-extensions" }, 195 | ] 196 | sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195 } 197 | wheels = [ 198 | { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000 }, 199 | { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996 }, 200 | { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957 }, 201 | { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199 }, 202 | { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296 }, 203 | { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109 }, 204 | { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028 }, 205 | { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044 }, 206 | { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881 }, 207 | { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034 }, 208 | { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187 }, 209 | { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628 }, 210 | { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866 }, 211 | { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894 }, 212 | { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688 }, 213 | { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808 }, 214 | { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580 }, 215 | { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859 }, 216 | { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810 }, 217 | { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498 }, 218 | { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611 }, 219 | { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924 }, 220 | { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196 }, 221 | { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389 }, 222 | { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223 }, 223 | { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473 }, 224 | { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269 }, 225 | { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921 }, 226 | { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162 }, 227 | { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560 }, 228 | { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777 }, 229 | ] 230 | 231 | [[package]] 232 | name = "pydantic-settings" 233 | version = "2.9.1" 234 | source = { registry = "https://pypi.org/simple" } 235 | dependencies = [ 236 | { name = "pydantic" }, 237 | { name = "python-dotenv" }, 238 | { name = "typing-inspection" }, 239 | ] 240 | sdist = { url = "https://files.pythonhosted.org/packages/67/1d/42628a2c33e93f8e9acbde0d5d735fa0850f3e6a2f8cb1eb6c40b9a732ac/pydantic_settings-2.9.1.tar.gz", hash = "sha256:c509bf79d27563add44e8446233359004ed85066cd096d8b510f715e6ef5d268", size = 163234 } 241 | wheels = [ 242 | { url = "https://files.pythonhosted.org/packages/b6/5f/d6d641b490fd3ec2c4c13b4244d68deea3a1b970a97be64f34fb5504ff72/pydantic_settings-2.9.1-py3-none-any.whl", hash = "sha256:59b4f431b1defb26fe620c71a7d3968a710d719f5f4cdbbdb7926edeb770f6ef", size = 44356 }, 243 | ] 244 | 245 | [[package]] 246 | name = "pygments" 247 | version = "2.19.1" 248 | source = { registry = "https://pypi.org/simple" } 249 | sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 } 250 | wheels = [ 251 | { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, 252 | ] 253 | 254 | [[package]] 255 | name = "python-dotenv" 256 | version = "1.1.0" 257 | source = { registry = "https://pypi.org/simple" } 258 | sdist = { url = "https://files.pythonhosted.org/packages/88/2c/7bb1416c5620485aa793f2de31d3df393d3686aa8a8506d11e10e13c5baf/python_dotenv-1.1.0.tar.gz", hash = "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5", size = 39920 } 259 | wheels = [ 260 | { url = "https://files.pythonhosted.org/packages/1e/18/98a99ad95133c6a6e2005fe89faedf294a748bd5dc803008059409ac9b1e/python_dotenv-1.1.0-py3-none-any.whl", hash = "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d", size = 20256 }, 261 | ] 262 | 263 | [[package]] 264 | name = "python-multipart" 265 | version = "0.0.20" 266 | source = { registry = "https://pypi.org/simple" } 267 | sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158 } 268 | wheels = [ 269 | { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546 }, 270 | ] 271 | 272 | [[package]] 273 | name = "rich" 274 | version = "14.0.0" 275 | source = { registry = "https://pypi.org/simple" } 276 | dependencies = [ 277 | { name = "markdown-it-py" }, 278 | { name = "pygments" }, 279 | ] 280 | sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078 } 281 | wheels = [ 282 | { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229 }, 283 | ] 284 | 285 | [[package]] 286 | name = "shellingham" 287 | version = "1.5.4" 288 | source = { registry = "https://pypi.org/simple" } 289 | sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310 } 290 | wheels = [ 291 | { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 }, 292 | ] 293 | 294 | [[package]] 295 | name = "sniffio" 296 | version = "1.3.1" 297 | source = { registry = "https://pypi.org/simple" } 298 | sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 } 299 | wheels = [ 300 | { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, 301 | ] 302 | 303 | [[package]] 304 | name = "sse-starlette" 305 | version = "2.3.3" 306 | source = { registry = "https://pypi.org/simple" } 307 | dependencies = [ 308 | { name = "anyio" }, 309 | { name = "starlette" }, 310 | ] 311 | sdist = { url = "https://files.pythonhosted.org/packages/86/35/7d8d94eb0474352d55f60f80ebc30f7e59441a29e18886a6425f0bccd0d3/sse_starlette-2.3.3.tar.gz", hash = "sha256:fdd47c254aad42907cfd5c5b83e2282be15be6c51197bf1a9b70b8e990522072", size = 17499 } 312 | wheels = [ 313 | { url = "https://files.pythonhosted.org/packages/5d/20/52fdb5ebb158294b0adb5662235dd396fc7e47aa31c293978d8d8942095a/sse_starlette-2.3.3-py3-none-any.whl", hash = "sha256:8b0a0ced04a329ff7341b01007580dd8cf71331cc21c0ccea677d500618da1e0", size = 10235 }, 314 | ] 315 | 316 | [[package]] 317 | name = "starlette" 318 | version = "0.46.2" 319 | source = { registry = "https://pypi.org/simple" } 320 | dependencies = [ 321 | { name = "anyio" }, 322 | ] 323 | sdist = { url = "https://files.pythonhosted.org/packages/ce/20/08dfcd9c983f6a6f4a1000d934b9e6d626cff8d2eeb77a89a68eef20a2b7/starlette-0.46.2.tar.gz", hash = "sha256:7f7361f34eed179294600af672f565727419830b54b7b084efe44bb82d2fccd5", size = 2580846 } 324 | wheels = [ 325 | { url = "https://files.pythonhosted.org/packages/8b/0c/9d30a4ebeb6db2b25a841afbb80f6ef9a854fc3b41be131d249a977b4959/starlette-0.46.2-py3-none-any.whl", hash = "sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35", size = 72037 }, 326 | ] 327 | 328 | [[package]] 329 | name = "typer" 330 | version = "0.15.3" 331 | source = { registry = "https://pypi.org/simple" } 332 | dependencies = [ 333 | { name = "click" }, 334 | { name = "rich" }, 335 | { name = "shellingham" }, 336 | { name = "typing-extensions" }, 337 | ] 338 | sdist = { url = "https://files.pythonhosted.org/packages/98/1a/5f36851f439884bcfe8539f6a20ff7516e7b60f319bbaf69a90dc35cc2eb/typer-0.15.3.tar.gz", hash = "sha256:818873625d0569653438316567861899f7e9972f2e6e0c16dab608345ced713c", size = 101641 } 339 | wheels = [ 340 | { url = "https://files.pythonhosted.org/packages/48/20/9d953de6f4367163d23ec823200eb3ecb0050a2609691e512c8b95827a9b/typer-0.15.3-py3-none-any.whl", hash = "sha256:c86a65ad77ca531f03de08d1b9cb67cd09ad02ddddf4b34745b5008f43b239bd", size = 45253 }, 341 | ] 342 | 343 | [[package]] 344 | name = "typing-extensions" 345 | version = "4.13.2" 346 | source = { registry = "https://pypi.org/simple" } 347 | sdist = { url = "https://files.pythonhosted.org/packages/f6/37/23083fcd6e35492953e8d2aaaa68b860eb422b34627b13f2ce3eb6106061/typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef", size = 106967 } 348 | wheels = [ 349 | { url = "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c", size = 45806 }, 350 | ] 351 | 352 | [[package]] 353 | name = "typing-inspection" 354 | version = "0.4.0" 355 | source = { registry = "https://pypi.org/simple" } 356 | dependencies = [ 357 | { name = "typing-extensions" }, 358 | ] 359 | sdist = { url = "https://files.pythonhosted.org/packages/82/5c/e6082df02e215b846b4b8c0b887a64d7d08ffaba30605502639d44c06b82/typing_inspection-0.4.0.tar.gz", hash = "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122", size = 76222 } 360 | wheels = [ 361 | { url = "https://files.pythonhosted.org/packages/31/08/aa4fdfb71f7de5176385bd9e90852eaf6b5d622735020ad600f2bab54385/typing_inspection-0.4.0-py3-none-any.whl", hash = "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f", size = 14125 }, 362 | ] 363 | 364 | [[package]] 365 | name = "uvicorn" 366 | version = "0.34.2" 367 | source = { registry = "https://pypi.org/simple" } 368 | dependencies = [ 369 | { name = "click" }, 370 | { name = "h11" }, 371 | ] 372 | sdist = { url = "https://files.pythonhosted.org/packages/a6/ae/9bbb19b9e1c450cf9ecaef06463e40234d98d95bf572fab11b4f19ae5ded/uvicorn-0.34.2.tar.gz", hash = "sha256:0e929828f6186353a80b58ea719861d2629d766293b6d19baf086ba31d4f3328", size = 76815 } 373 | wheels = [ 374 | { url = "https://files.pythonhosted.org/packages/b1/4b/4cef6ce21a2aaca9d852a6e84ef4f135d99fcd74fa75105e2fc0c8308acd/uvicorn-0.34.2-py3-none-any.whl", hash = "sha256:deb49af569084536d269fe0a6d67e3754f104cf03aba7c11c40f01aadf33c403", size = 62483 }, 375 | ] 376 | --------------------------------------------------------------------------------