Author SHA1 Message Date
armistace 1d18a37fa7 Merge branch 'master' into ci-speed-optimizations 2026-07-28 11:08:19 +10:00
armistace a1a534a86c Merge pull request 'bump all timeouts to 60 minutes for large context models' (#28) from bump-timeouts-60min into master
Create Blog Article if new notes exist / prepare_blog_drafts_and_push (push) Has been cancelled
Reviewed-on: #28
2026-07-28 11:07:43 +10:00
Hermes Agent c86d6e4e4d speed up CI dependency installation 2026-07-28 10:44:00 +10:00
Hermes Agent 5e014f50a5 bump all timeouts to 60 minutes for large context models 2026-07-28 10:38:09 +10:00
Hermes Agent d488c2be1d ci: retry after model swap 2026-07-28 10:32:43 +10:00
armistace 6d2b043eca Merge pull request 'udpate chromadb import to be lazy' (#27) from fix-random-illegal-instruction into master
Create Blog Article if new notes exist / prepare_blog_drafts_and_push (push) Failing after 28m29s
Reviewed-on: #27
2026-05-21 22:44:37 +10:00
armistace fa611192c8 reviewer fix 2026-05-21 22:44:04 +10:00
armistace e69b83694c udpate chromadb import to be lazy 2026-05-21 21:28:03 +10:00
armistace 1781a1dbf5 Merge pull request 'update repo manager to work of master not main' (#22) from git-creation-issue into master
Create Blog Article if new notes exist / prepare_blog_drafts_and_push (push) Failing after 10m5s
Reviewed-on: #22
2026-04-29 21:58:43 +10:00
armistace 64acdb29b2 update repo manager to work of master not main 2026-04-29 21:58:16 +10:00
5 changed files with 35 additions and 16 deletions
+5 -5
View File
@@ -15,12 +15,12 @@ jobs:
- name: Install dependencies - name: Install dependencies
shell: bash shell: bash
run: | run: |
apt update && apt upgrade -y apt update -qq
apt install rustc cargo python-is-python3 pip python3-venv python3-virtualenv libmagic-dev git -y apt install -y -qq python-is-python3 pip python3-venv libmagic-dev git
virtualenv .venv python -m venv .venv
source .venv/bin/activate source .venv/bin/activate
pip install --upgrade pip pip install --upgrade pip -q
pip install -r requirements.txt pip install -r requirements.txt --prefer-binary -q
git config --global user.name "Blog Creator" git config --global user.name "Blog Creator"
git config --global user.email "ridgway.infrastructure@gmail.com" git config --global user.email "ridgway.infrastructure@gmail.com"
git config --global push.autoSetupRemote true git config --global push.autoSetupRemote true
+23 -4
View File
@@ -17,14 +17,19 @@ journalist draft is chunked, embedded, and stored in a collection; the editor
receives the top-N most relevant chunks as context. receives the top-N most relevant chunks as context.
""" """
from __future__ import annotations
import json import json
import os import os
import random import random
import re import re
import string import string
from datetime import datetime from datetime import datetime
from typing import TYPE_CHECKING
if TYPE_CHECKING:
import chromadb # noqa: F811
import chromadb
from crewai.flow.flow import Flow, listen, start from crewai.flow.flow import Flow, listen, start
from ollama import Client from ollama import Client
from pydantic import BaseModel, ConfigDict from pydantic import BaseModel, ConfigDict
@@ -85,7 +90,21 @@ class BlogFlow(Flow[BlogFlowState]):
) )
@staticmethod @staticmethod
def _get_chroma_client() -> chromadb.HttpClient: def _get_chroma_client() -> "chromadb.HttpClient":
# Lazily import chromadb here rather than at module level.
# chromadb unconditionally loads hnswlib (a native C++ library
# compiled with AVX instructions) even when using HttpClient
# to talk to an external ChromaDB server. Deferring the import
# avoids "Illegal instruction" (SIGILL) crashes in environments
# that lack AVX support (e.g. act, older CI runners).
try:
import chromadb
except ImportError as exc:
raise RuntimeError(
"chromadb is required for the editor phase but could not be "
f"imported: {exc}"
) from exc
chroma_port = int(os.environ["CHROMA_PORT"]) chroma_port = int(os.environ["CHROMA_PORT"])
return chromadb.HttpClient(host=os.environ["CHROMA_HOST"], port=chroma_port) return chromadb.HttpClient(host=os.environ["CHROMA_HOST"], port=chroma_port)
@@ -127,7 +146,7 @@ class BlogFlow(Flow[BlogFlowState]):
print(f"Error generating embeddings: {exc}") print(f"Error generating embeddings: {exc}")
return [] return []
def _load_drafts_to_vector_db(self, drafts: list[str]) -> chromadb.Collection: def _load_drafts_to_vector_db(self, drafts: list[str]) -> "chromadb.Collection":
"""Load journalist drafts into a new ChromaDB collection and return it.""" """Load journalist drafts into a new ChromaDB collection and return it."""
chroma = self._get_chroma_client() chroma = self._get_chroma_client()
collection_name = ( collection_name = (
@@ -165,7 +184,7 @@ class BlogFlow(Flow[BlogFlowState]):
return collection return collection
@staticmethod @staticmethod
def _query_vector_db(collection: chromadb.Collection, query_text: str) -> str: def _query_vector_db(collection: "chromadb.Collection", query_text: str) -> str:
"""Query the ChromaDB collection and return the most relevant """Query the ChromaDB collection and return the most relevant
document chunks joined as a single string.""" document chunks joined as a single string."""
ollama_client = BlogFlow._get_ollama_client() ollama_client = BlogFlow._get_ollama_client()
+2 -2
View File
@@ -140,8 +140,8 @@ class OllamaGenerator:
) )
return response["message"]["content"] return response["message"]["content"]
# Retry mechanism with 30-minute timeout (same as the original) # Retry mechanism with 60-minute timeout (bumped for large context models)
timeout_seconds = 30 * 60 timeout_seconds = 60 * 60
max_retries = 3 max_retries = 3
for attempt in range(max_retries): for attempt in range(max_retries):
@@ -102,7 +102,7 @@ class OllamaWebSearchTool(BaseTool):
"Authorization": f"Bearer {api_key}", "Authorization": f"Bearer {api_key}",
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
timeout=30.0, timeout=60.0,
) )
# Raise for HTTP errors so we can catch them with specific messages # Raise for HTTP errors so we can catch them with specific messages
+4 -4
View File
@@ -42,7 +42,7 @@ class GitRepository:
print(f"Cloning failed: {e}") print(f"Cloning failed: {e}")
return False return False
def fetch(self, remote_name="origin", ref_name="main"): def fetch(self, remote_name="origin", ref_name="master"):
"""Fetch updates from a remote repository with authentication""" """Fetch updates from a remote repository with authentication"""
try: try:
self.repo.remotes[remote_name].fetch(ref_name=ref_name) self.repo.remotes[remote_name].fetch(ref_name=ref_name)
@@ -51,7 +51,7 @@ class GitRepository:
print(f"Fetching failed: {e}") print(f"Fetching failed: {e}")
return False return False
def pull(self, remote_name="origin", ref_name="main"): def pull(self, remote_name="origin", ref_name="master"):
"""Pull updates from a remote repository with authentication""" """Pull updates from a remote repository with authentication"""
print("Pulling Latest Updates (if any)") print("Pulling Latest Updates (if any)")
try: try:
@@ -93,8 +93,8 @@ class GitRepository:
self.repo.git.checkout(title) self.repo.git.checkout(title)
self.pull(ref_name=title) self.pull(ref_name=title)
else: else:
# New branch, create from main # New branch, create from master
self.repo.git.checkout("-b", title, "origin/main") self.repo.git.checkout("-b", title, "origin/master")
# Ensure destination directory exists # Ensure destination directory exists
dest_dir = f"{self.repo_path}src/content/" dest_dir = f"{self.repo_path}src/content/"