├── .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 | [](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 |
--------------------------------------------------------------------------------