diff --git a/.github/workflows/generate-changelog.yml b/.github/workflows/generate-changelog.yml new file mode 100644 index 000000000..f23ebc7c8 --- /dev/null +++ b/.github/workflows/generate-changelog.yml @@ -0,0 +1,82 @@ +name: Julep-Changelog-Generation + +on: + workflow_dispatch: {} + +jobs: + changelog_generation: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: dev + + - name: Setup GitHub CLI + run: | + echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token + + - name: Collect merged PRs from the last two weeks + id: collect_prs + run: | + if [[ "$OSTYPE" == "darwin"* ]]; then + date_threshold=$(date -v-14d +"%Y-%m-%d") + else + date_threshold=$(date -d '-14 days' +"%Y-%m-%d") + fi + + echo "Fetching merged PRs since $date_threshold..." + + merged_prs=$( + gh pr list --state merged --json number,title,body,author \ + --search "merged:>=$date_threshold" \ + --jq 'map({number, title, body, author: .author.login})' + ) + + if [ -z "$merged_prs" ] || [ "$merged_prs" = "null" ]; then + echo "No merged PRs found in the last two weeks." + echo "pr_data=[]" >> $GITHUB_ENV + echo '{"pr_data": []}' > pr_data.json + exit 0 + fi + + echo "pr_data=$merged_prs" >> $GITHUB_ENV + echo "{\"pr_data\": $merged_prs}" > pr_data.json + + - name: Setup Python v3.10.12 + uses: actions/setup-python@v5 + with: + python-version: "3.10.12" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install PyYAML julep + + - name: Send PR data to Python script + if: steps.collect_prs.outputs.pr_data != '[]' + id: generate_changelog + run: | + if ! python scripts/generate_changelog.py; then + echo "Error: Failed to generate changelog" + exit 1 + fi + env: + JULEP_API_KEY: ${{ secrets.JULEP_API_KEY }} + TASK_UUID: ${{ secrets.TASK_UUID }} + AGENT_UUID: ${{ secrets.AGENT_UUID }} + + - name: Create Pull Request + if: success() && steps.collect_prs.outputs.pr_data != '[]' + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "chore(changelog): update CHANGELOG.md" + title: "Update CHANGELOG.md" + body: "This PR updates the changelog with PRs from the last 2 weeks." + branch: "update-changelog" + delete-branch: true + add-paths: | + CHANGELOG.md diff --git a/agents-api/agents_api/activities/execute_system.py b/agents-api/agents_api/activities/execute_system.py index 8d85a2639..bc2bcd8cf 100644 --- a/agents-api/agents_api/activities/execute_system.py +++ b/agents-api/agents_api/activities/execute_system.py @@ -6,7 +6,6 @@ from beartype import beartype from box import Box, BoxList -from fastapi import HTTPException from fastapi.background import BackgroundTasks from temporalio import activity @@ -110,6 +109,7 @@ async def execute_system( await bg_runner() return res + # Handle create operations if system.operation == "create" and system.resource == "session": developer_id = arguments.pop("developer_id") session_id = arguments.pop("session_id", None) diff --git a/agents-api/agents_api/activities/utils.py b/agents-api/agents_api/activities/utils.py index d9ad1840c..5b12d34e0 100644 --- a/agents-api/agents_api/activities/utils.py +++ b/agents-api/agents_api/activities/utils.py @@ -303,6 +303,7 @@ def get_handler(system: SystemDef) -> Callable: from ..models.agent.update_agent import update_agent as update_agent_query from ..models.docs.delete_doc import delete_doc as delete_doc_query from ..models.docs.list_docs import list_docs as list_docs_query + from ..models.entry.get_history import get_history as get_history_query from ..models.session.create_session import create_session as create_session_query from ..models.session.delete_session import delete_session as delete_session_query from ..models.session.get_session import get_session as get_session_query @@ -376,6 +377,8 @@ def get_handler(system: SystemDef) -> Callable: return delete_session_query case ("session", None, "chat"): return chat + case ("session", None, "history"): + return get_history_query # TASKS case ("task", None, "list"): diff --git a/agents-api/agents_api/autogen/Docs.py b/agents-api/agents_api/autogen/Docs.py index ffed27c1d..ca3371920 100644 --- a/agents-api/agents_api/autogen/Docs.py +++ b/agents-api/agents_api/autogen/Docs.py @@ -14,11 +14,17 @@ class BaseDocSearchRequest(BaseModel): populate_by_name=True, ) limit: Annotated[int, Field(ge=1, le=50)] = 10 + """ + The limit of documents to return + """ lang: Literal["en-US"] = "en-US" """ The language to be used for text-only search. Support for other languages coming soon. """ metadata_filter: dict[str, Any] = {} + """ + Metadata filter to apply to the search + """ mmr_strength: Annotated[float, Field(ge=0.0, lt=1.0)] = 0 """ MMR Strength (mmr_strength = 1 - mmr_lambda) diff --git a/agents-api/agents_api/autogen/Sessions.py b/agents-api/agents_api/autogen/Sessions.py index 460fd25ce..c14b8f96e 100644 --- a/agents-api/agents_api/autogen/Sessions.py +++ b/agents-api/agents_api/autogen/Sessions.py @@ -96,10 +96,41 @@ class RecallOptions(BaseModel): populate_by_name=True, ) mode: Literal["hybrid", "vector", "text"] = "vector" + """ + The mode to use for the search. + """ num_search_messages: int = 4 + """ + The number of search messages to use for the search. + """ max_query_length: int = 1000 - hybrid_alpha: float = 0.7 - confidence: float = 0.6 + """ + The maximum query length to use for the search. + """ + alpha: Annotated[float, Field(ge=0.0, le=1.0)] = 0.7 + """ + The weight to apply to BM25 vs Vector search results. 0 => pure BM25; 1 => pure vector; + """ + confidence: Annotated[float, Field(ge=0.0, le=1.0)] = 0.6 + """ + The confidence cutoff level + """ + limit: Annotated[int, Field(ge=1, le=50)] = 10 + """ + The limit of documents to return + """ + lang: Literal["en-US"] = "en-US" + """ + The language to be used for text-only search. Support for other languages coming soon. + """ + metadata_filter: dict[str, Any] = {} + """ + Metadata filter to apply to the search + """ + mmr_strength: Annotated[float, Field(ge=0.0, lt=1.0)] = 0 + """ + MMR Strength (mmr_strength = 1 - mmr_lambda) + """ class RecallOptionsUpdate(RecallOptions): diff --git a/agents-api/agents_api/models/chat/gather_messages.py b/agents-api/agents_api/models/chat/gather_messages.py index 28dc6607f..cf444e921 100644 --- a/agents-api/agents_api/models/chat/gather_messages.py +++ b/agents-api/agents_api/models/chat/gather_messages.py @@ -1,15 +1,18 @@ -from typing import TypeVar +from typing import Any, Dict, List, Optional, Tuple, TypeVar, Union from uuid import UUID +import numpy as np from beartype import beartype from fastapi import HTTPException from pycozo.client import QueryException from pydantic import ValidationError from ...autogen.openapi_model import ChatInput, DocReference, History +from ...autogen.Sessions import RecallOptions from ...clients import litellm from ...common.protocol.developers import Developer from ...common.protocol.sessions import ChatContext +from ...models.docs.mmr import maximal_marginal_relevance from ..docs.search_docs_by_embedding import search_docs_by_embedding from ..docs.search_docs_by_text import search_docs_by_text from ..docs.search_docs_hybrid import search_docs_hybrid @@ -23,6 +26,52 @@ T = TypeVar("T") +def get_search_fn_and_params( + recall_options: RecallOptions, + query_text: str | None, + query_embedding: list[float] | None, +) -> Tuple[ + Any, + Optional[Dict[str, Union[float, int, str, Dict[str, float], List[float], None]]], +]: + search_fn, params = None, None + + match recall_options.mode: + case "text": + search_fn = search_docs_by_text + params = dict( + query=query_text, + k=recall_options.limit, + metadata_filter=recall_options.metadata_filter, + ) + + case "vector": + search_fn = search_docs_by_embedding + params = dict( + query_embedding=query_embedding, + k=recall_options.limit * 3 + if recall_options.mmr_strength > 0 + else recall_options.limit, + confidence=recall_options.confidence, + metadata_filter=recall_options.metadata_filter, + ) + + case "hybrid": + search_fn = search_docs_hybrid + params = dict( + query=query_text, + query_embedding=query_embedding, + k=recall_options.limit * 3 + if recall_options.mmr_strength > 0 + else recall_options.limit, + embed_search_options=dict(confidence=recall_options.confidence), + alpha=recall_options.alpha, + metadata_filter=recall_options.metadata_filter, + ) + + return search_fn, params + + @rewrap_exceptions( { QueryException: partialclass(HTTPException, status_code=400), @@ -98,44 +147,62 @@ async def gather_messages( ] ).strip() - [query_embedding, *_] = await litellm.aembedding( - # Truncate on the left to keep the last `search_query_chars` characters - inputs=embed_text[-(recall_options.max_query_length) :], - # TODO: Make this configurable once it's added to the ChatInput model - embed_instruction="Represent the query for retrieving supporting documents: ", - ) + # Set the query text and embedding + query_text, query_embedding = None, None + + # Embed the query + if recall_options.mode != "text": + [query_embedding, *_] = await litellm.aembedding( + # Truncate on the left to keep the last `search_query_chars` characters + inputs=embed_text[-(recall_options.max_query_length) :], + # TODO: Make this configurable once it's added to the ChatInput model + embed_instruction="Represent the query for retrieving supporting documents: ", + ) # Truncate on the right to take only the first `search_query_chars` characters - query_text = search_messages[-1]["content"].strip()[ - : recall_options.max_query_length - ] + if recall_options.mode == "text" or recall_options.mode == "hybrid": + query_text = search_messages[-1]["content"].strip()[ + : recall_options.max_query_length + ] # List all the applicable owners to search docs from active_agent_id = chat_context.get_active_agent().id user_ids = [user.id for user in chat_context.users] owners = [("user", user_id) for user_id in user_ids] + [("agent", active_agent_id)] + # Get the search function and parameters + search_fn, params = get_search_fn_and_params( + recall_options=recall_options, + query_text=query_text, + query_embedding=query_embedding, + ) + # Search for doc references - doc_references: list[DocReference] = [] - match recall_options.mode: - case "vector": - doc_references: list[DocReference] = search_docs_by_embedding( - developer_id=developer.id, - owners=owners, - query_embedding=query_embedding, - ) - case "hybrid": - doc_references: list[DocReference] = search_docs_hybrid( - developer_id=developer.id, - owners=owners, - query=query_text, - query_embedding=query_embedding, - ) - case "text": - doc_references: list[DocReference] = search_docs_by_text( - developer_id=developer.id, - owners=owners, - query=query_text, - ) + doc_references: list[DocReference] = search_fn( + developer_id=developer.id, + owners=owners, + **params, + ) + + # Apply MMR if enabled + if ( + # MMR is enabled + recall_options.mmr_strength > 0 + # The number of doc references is greater than the limit + and len(doc_references) > recall_options.limit + # MMR is not applied to text search + and recall_options.mode != "text" + ): + # Apply MMR + indices = maximal_marginal_relevance( + np.asarray(query_embedding), + [doc.snippet.embedding for doc in doc_references], + k=recall_options.limit, + ) + # Apply MMR + doc_references = [ + doc for i, doc in enumerate(doc_references) if i in set(indices) + ] + # Return the past messages and doc references return past_messages, doc_references diff --git a/agents-api/agents_api/workflows/task_execution/transition.py b/agents-api/agents_api/workflows/task_execution/transition.py index a26ac1778..c6197fed1 100644 --- a/agents-api/agents_api/workflows/task_execution/transition.py +++ b/agents-api/agents_api/workflows/task_execution/transition.py @@ -14,7 +14,6 @@ from ...common.retry_policies import DEFAULT_RETRY_POLICY from ...env import ( debug, - temporal_activity_after_retry_timeout, temporal_heartbeat_timeout, temporal_schedule_to_close_timeout, testing, diff --git a/agents-api/tests/test_chat_routes.py b/agents-api/tests/test_chat_routes.py index 4838efcd5..2c6567b04 100644 --- a/agents-api/tests/test_chat_routes.py +++ b/agents-api/tests/test_chat_routes.py @@ -87,9 +87,13 @@ async def _( agent=agent.id, situation="test session about", recall_options={ - "mode": "text", - "num_search_messages": 10, - "max_query_length": 1001, + "mode": "hybrid", + "num_search_messages": 6, + "max_query_length": 800, + "confidence": 0.6, + "alpha": 0.7, + "limit": 10, + "mmr_strength": 0.5, }, ), client=client, @@ -135,9 +139,12 @@ async def _( agent=agent.id, situation="test session about", recall_options={ - "mode": "vector", - "num_search_messages": 5, + "mode": "text", + "num_search_messages": 10, "max_query_length": 1001, + "confidence": 0.6, + "limit": 5, + "mmr_strength": 0.5, }, ), client=client, diff --git a/agents-api/tests/test_execution_workflow.py b/agents-api/tests/test_execution_workflow.py index e733f81c0..ae440ff02 100644 --- a/agents-api/tests/test_execution_workflow.py +++ b/agents-api/tests/test_execution_workflow.py @@ -16,7 +16,6 @@ from agents_api.models.task.create_task import create_task from agents_api.routers.tasks.create_task_execution import start_execution from tests.fixtures import ( - async_cozo_client, cozo_client, cozo_clients_with_migrations, test_agent, diff --git a/integrations-service/integrations/autogen/Docs.py b/integrations-service/integrations/autogen/Docs.py index ffed27c1d..ca3371920 100644 --- a/integrations-service/integrations/autogen/Docs.py +++ b/integrations-service/integrations/autogen/Docs.py @@ -14,11 +14,17 @@ class BaseDocSearchRequest(BaseModel): populate_by_name=True, ) limit: Annotated[int, Field(ge=1, le=50)] = 10 + """ + The limit of documents to return + """ lang: Literal["en-US"] = "en-US" """ The language to be used for text-only search. Support for other languages coming soon. """ metadata_filter: dict[str, Any] = {} + """ + Metadata filter to apply to the search + """ mmr_strength: Annotated[float, Field(ge=0.0, lt=1.0)] = 0 """ MMR Strength (mmr_strength = 1 - mmr_lambda) diff --git a/integrations-service/integrations/autogen/Sessions.py b/integrations-service/integrations/autogen/Sessions.py index 460fd25ce..c14b8f96e 100644 --- a/integrations-service/integrations/autogen/Sessions.py +++ b/integrations-service/integrations/autogen/Sessions.py @@ -96,10 +96,41 @@ class RecallOptions(BaseModel): populate_by_name=True, ) mode: Literal["hybrid", "vector", "text"] = "vector" + """ + The mode to use for the search. + """ num_search_messages: int = 4 + """ + The number of search messages to use for the search. + """ max_query_length: int = 1000 - hybrid_alpha: float = 0.7 - confidence: float = 0.6 + """ + The maximum query length to use for the search. + """ + alpha: Annotated[float, Field(ge=0.0, le=1.0)] = 0.7 + """ + The weight to apply to BM25 vs Vector search results. 0 => pure BM25; 1 => pure vector; + """ + confidence: Annotated[float, Field(ge=0.0, le=1.0)] = 0.6 + """ + The confidence cutoff level + """ + limit: Annotated[int, Field(ge=1, le=50)] = 10 + """ + The limit of documents to return + """ + lang: Literal["en-US"] = "en-US" + """ + The language to be used for text-only search. Support for other languages coming soon. + """ + metadata_filter: dict[str, Any] = {} + """ + Metadata filter to apply to the search + """ + mmr_strength: Annotated[float, Field(ge=0.0, lt=1.0)] = 0 + """ + MMR Strength (mmr_strength = 1 - mmr_lambda) + """ class RecallOptionsUpdate(RecallOptions): diff --git a/memory-store/Dockerfile b/memory-store/Dockerfile index fa384cb12..b6b99b40c 100644 --- a/memory-store/Dockerfile +++ b/memory-store/Dockerfile @@ -16,8 +16,8 @@ RUN apt-get update && apt-get install -y \ # Build cozo-ce-bin from crates.io WORKDIR /usr/src -# RUN cargo install cozo-ce-bin@0.7.13-alpha.3 --features "requests graph-algo storage-new-rocksdb storage-sqlite jemalloc io-uring malloc-usable-size" -RUN cargo install --git https://github.com/cozo-community/cozo.git --branch f/publish-crate --rev 592f49b --profile release -F graph-algo -F jemalloc -F io-uring -F storage-new-rocksdb -F malloc-usable-size --target x86_64-unknown-linux-gnu cozo-ce-bin +RUN cargo install cozo-ce-bin@0.7.13-alpha.3 --features "requests graph-algo storage-new-rocksdb storage-sqlite jemalloc io-uring malloc-usable-size" +# RUN cargo install --git https://github.com/cozo-community/cozo.git --branch f/publish-crate --rev 592f49b --profile release -F graph-algo -F jemalloc -F io-uring -F storage-new-rocksdb -F malloc-usable-size --target x86_64-unknown-linux-gnu cozo-ce-bin # Copy the built binary to /usr/local/bin RUN cp /usr/local/cargo/bin/cozo-ce-bin /usr/local/bin/cozo diff --git a/scripts/generate_changelog.py b/scripts/generate_changelog.py new file mode 100644 index 000000000..3cb56d49b --- /dev/null +++ b/scripts/generate_changelog.py @@ -0,0 +1,189 @@ +# Standard library imports +import sys +import json +import re +import logging +from pathlib import Path +import os +import time +from typing import List, Dict, Any + +# Third-party imports +from julep import Client +import yaml + +# Configure logging with timestamp, level, and message format +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') + +# Constants and configurations +HTML_TAGS_PATTERN = re.compile(r"(<[^>]+>)") # Regex pattern to match HTML tags +REQUIRED_ENV_VARS = ['AGENT_UUID', 'TASK_UUID', 'JULEP_API_KEY'] # List of required environment variables + +def load_template(filename: str) -> str: + """Load template content from file""" + return Path(f'./scripts/templates/{filename}').read_text(encoding='utf-8') + +def run_task(pr_data: str) -> str: + """ + Execute the changelog generation task using Julep API. + + Args: + pr_data (str): Formatted PR data to process + + Returns: + str: Generated changelog content + + Raises: + ValueError: If required environment variables are missing + Exception: If task execution fails + """ + # Validate env vars with list comprehension + if missing_vars := [var for var in REQUIRED_ENV_VARS if not os.environ.get(var)]: + raise ValueError(f"Missing required environment variables: {', '.join(missing_vars)}") + + client = Client(api_key=os.environ['JULEP_API_KEY'], environment="dev") + + # Use context manager for file operations + with Path('./scripts/templates/changelog.yaml').open(encoding='utf-8') as f: + task_description = yaml.safe_load(f) + + # Create or update the AI agent + agent = client.agents.create_or_update( + agent_id=os.environ['AGENT_UUID'], + name="Changelog Generator", + about="An AI assistant that can generate a changelog from a list of PRs.", + model="gpt-4o", + ) + + # Create or update the task configuration + task = client.tasks.create_or_update( + task_id=os.environ['TASK_UUID'], + agent_id=os.environ['AGENT_UUID'], + **task_description + ) + + # Create a new execution instance + execution = client.executions.create( + task_id=os.environ['TASK_UUID'], + input={"pr_data": str(pr_data)} + ) + + # Wait for task completion using context manager for proper resource cleanup + with client: + while (result := client.executions.get(execution.id)).status not in ['succeeded', 'failed']: + time.sleep(3) + + if result.status != "succeeded": + raise Exception(result.error) + return result.output + +def preserve_and_update_changelog(new_changelog: str, source: str = './CHANGELOG.md') -> None: + """ + Save the generated changelog while preserving HTML content. + + Args: + new_changelog (str): The new changelog content to save + source (str): Path to the changelog file (default: 'CHANGELOG.md') + """ + path = Path(source) + path.parent.mkdir(parents=True, exist_ok=True) + + # Load templates at runtime + html_content = load_template('header.html') + author_list = load_template('authors.md') + + content = f"{html_content}\n\n{new_changelog}\n\n{author_list}" + path.write_text(content, encoding='utf-8') + +def is_html_tag(segment: str) -> bool: + """ + Check if a given string segment is an HTML tag. + + Args: + segment (str): String to check + + Returns: + bool: True if segment is an HTML tag, False otherwise + """ + return re.fullmatch(HTML_TAGS_PATTERN, segment) is not None + +def process_body(body: str) -> str: + """ + Process PR body text by removing HTML tags and special markers. + + Args: + body (str): PR description body text + + Returns: + str: Cleaned and processed body text + """ + if not body: + return "" + + # Remove HTML tags and clean up the text + segments = [seg for seg in re.split(HTML_TAGS_PATTERN, body) if not is_html_tag(seg)] + processed_body = "".join(segments) + return processed_body.replace(">", "").replace("[!IMPORTANT]", "").strip() + +def process_pr_data(pr_data: str) -> str: + """ + Generate changelog entries from PR data. + + Args: + pr_data (str): JSON string containing PR information + + Returns: + str: Formatted changelog entries + """ + prs: List[Dict[str, Any]] = json.loads(pr_data) + + # Use list comprehension with f-strings + entries = [ + f"""- PR #{pr['number']}: {pr['title']} + Author: {pr['author']} + Body: + {process_body(pr.get('body', ''))} + """ + for pr in prs + ] + return "\n".join(entries) + +def main(pr_data: str) -> None: + """ + Main function to orchestrate changelog generation process. + + Args: + pr_data (str): JSON string containing PR information + + Raises: + Exception: If any step in the process fails + """ + try: + logging.info("Processing PR data...") + processed_pr_data = process_pr_data(pr_data) + + logging.info("Running task...") + final_changelog = run_task(processed_pr_data) + + logging.info("Saving changelog...") + preserve_and_update_changelog(final_changelog) + + logging.info("Successfully saved changelog to CHANGELOG.md") + + # delete the pr_data.json file + os.remove('pr_data.json') + logging.info("Deleted pr_data.json file") + except Exception as e: + logging.error(f"Failed to generate changelog: {str(e)}") + raise + +# Script entry point +if __name__ == "__main__": + try: + # Read PR data from JSON file + with open('pr_data.json', 'r') as file: + pr_data = json.load(file) + main(pr_data) + except Exception as e: + logging.error(f"Script failed: {str(e)}") + sys.exit(1) \ No newline at end of file diff --git a/scripts/templates/authors.md b/scripts/templates/authors.md new file mode 100644 index 000000000..962b95f5e --- /dev/null +++ b/scripts/templates/authors.md @@ -0,0 +1,9 @@ +## Contributors + +Thank you to all our contributors who helped make this release possible! + +- [Dmitry Paramonov](https://github.com/whiterabbit1983) π +- [Ahmad Haidar](https://github.com/Ahmad-mtos) π +- [Diwank Tomar](https://github.com/creatorrr) π +- [Vedant Sahai](https://github.com/Vedantsahai18) π₯ +- [Hamada Salhab](https://github.com/HamadaSalhab) π‘ \ No newline at end of file diff --git a/scripts/templates/changelog.yaml b/scripts/templates/changelog.yaml new file mode 100644 index 000000000..c6254e634 --- /dev/null +++ b/scripts/templates/changelog.yaml @@ -0,0 +1,111 @@ +name: Changelog Generator +description: Generates a changelog from a list of PRs. + +main: +- prompt: + - role: system + content: | + # AI Agent Prompt for Generating a Structured and Engaging Changelog + + Generate a **detailed** and **engaging changelog** based on information from the PR comment, title, author, and any additional context. + Your goal is to make the changelog both **informative** and **appealing** to the user. + + ## π Steps to Generate the Changelog: + + ### 1. **Extract Relevant Information** π + Gather all the important details from the following sources: + - **PR Title**: What is the overall summary of the change? + - **PR Comment**: Any detailed description of the changes and reasons for the change. + - **PR Author**: Who made the change? (Include name or GitHub handle) + - **Additional Context**: Include any extra context or notes provided for a clearer understanding of the changes. + + ### 2. **Organize the Content** ποΈ + Structure the changelog into **clear sections**. These sections should be: + - **Features** β¨: New functionalities or major additions. + - **Fixes** π§: Bug fixes or issue resolutions. + - **Improvements** π: Enhancements or optimizations made. + - **Performance Enhancements** π: Changes that improve speed, efficiency, or scalability. + - **Breaking Changes** π₯: Changes that could potentially break backward compatibility. + + ### 3. **Detail the Changes** π + For each section, include: + - A **concise but clear description** of what has changed. + - The **reason** behind the change (why it was needed). + - The **benefit** or **impact** on the user experience. + + ### 4. **Engage the User** π£οΈ + Write in a conversational and engaging tone. Try to: + - Highlight the **key updates** and their **user impact**. + - Encourage users to **take action** if necessary (e.g., βPlease upgrade to this version to experience the new feature!β). + + ### 5. **Format the Changelog** ποΈ + Make sure the changelog is visually clear and easy to read: + - Use **bullet points** for each change. + - Apply **headings** for sections like "Features", "Fixes", etc. + - Use **emojis** to visually separate and highlight sections. + + ### 6. **Output Format** ποΈ + The final changelog should follow this format: + - **Title**: "Julep AI Changelog for 12th December 2024" (Note: Use `datetime.datetime.now().strftime('%d %B %Y')` for auto-generating the date). + - **Sections**: Start with a header for each section (e.g., `## Features β¨`) and list items under it in bullet points. + - Use **bold** and **italic** where needed to emphasize key points. + + The final changelog should be **engaging**, **well-structured**, and easy to read, making it accessible to both technical and non-technical users. + + Here are certain notes that you should follow: + - The output should be in markdown format as the output will be rendered in a markdown file. + - Wherever possible describe the changes in a way that is more engaging and conversational. + - Make it as visually appealing as possible. Add emojis to make it more engaging. + - Add empty lines between sections and make sure the output is formatted correctly. + - Add a footer with the all authors of the changelog at the bottom. + - Ensure that the output is formatted correctly. + - No need to add a footer or author list or contributors list. + + Please feel free to make changes to the output as you see fit. You only need to return me the changelog and nothing else. + Add markdown formatting to the output wherever needed to make it more visual attractive, readable and engaging. + + ### Example Output: + + # **Julep AI Changelog for {{datetime.datetime.now().strftime('%d %B %Y')}}** β¨ + + ## **Features** β¨ + - **Real-Time Analytics Dashboard**: A brand-new dashboard that provides real-time data visualizations of user activity. + - **Why**: We needed a way to track live data for quicker decision-making. + - **Impact**: Users can now see real-time metrics to improve decision-making on-the-go. + + ## **Fixes** π§ + - **Fixed an Issue with Data Export**: Resolved a bug preventing users from exporting large data sets. + - **Why**: Export failures were occurring due to improper handling of large files. + - **Impact**: Users can now export data without encountering errors. + + ## **Improvements** π + - **Improved Search Functionality**: The search engine now returns results 20% faster. + - **Why**: To ensure quicker access to information. + - **Impact**: Users will notice faster search results, improving overall efficiency. + + ## **Performance Enhancements** π + - **Optimized Data Compression**: Reduced the size of stored data by 30%. + - **Why**: To make data storage more efficient. + - **Impact**: Faster data retrieval times and less storage usage. + + ## **Breaking Changes** π₯ + - **Deprecated Legacy API**: The old API version (v1) will no longer be supported from next month. + - **Why**: Weβve moved to a more secure and feature-rich version. + - **Impact**: Developers must upgrade to API v2 to continue using our services. + + ## **Notes** π + - Please **update your version** to avoid issues with deprecated features. + - Known issues: Some users may experience temporary delays due to high traffic on the server. + + ## π Key Notes: + - **Clarity**: Use clear, non-technical language where possible. + - **Version Specifics**: Mention if a particular version or update is affected by the changes. + - **Known Issues**: Document any known issues, especially those that might impact the user experience. + + - role: user + content: | + Here is the PR data: + + {{inputs[0]['pr_data']}} + + unwrap: true \ No newline at end of file diff --git a/scripts/templates/header.html b/scripts/templates/header.html new file mode 100644 index 000000000..50dd9f569 --- /dev/null +++ b/scripts/templates/header.html @@ -0,0 +1,24 @@ +
+
+ Explore Docs (wip)
+ Β·
+ Discord
+ Β·
+ π
+ Β·
+ LinkedIn
+