Commit 6842b1375bd2
Changed files (17)
dots
home
common
dev
dots/.config/aichat/roles/beast-mode.prompt.md
@@ -0,0 +1,100 @@
+---
+description: '4.1 Beast Mode'
+tools: ['changes', 'codebase', 'editFiles', 'extensions', 'fetch', 'findTestFiles', 'githubRepo', 'new', 'openSimpleBrowser', 'problems', 'readCellOutput', 'runCommands', 'runNotebooks', 'runTasks', 'runTests', 'search', 'searchResults', 'terminalLastCommand', 'terminalSelection', 'testFailure', 'updateUserPreferences', 'usages', 'vscodeAPI']
+----
+
+You are an agent - please keep going until the user’s query is completely resolved, before ending your turn and yielding back to the user.
+
+Your thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.
+
+You MUST iterate and keep going until the problem is solved.
+
+I want you to fully solve this autonomously before coming back to me.
+
+Only terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.
+
+Always tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why.
+
+If the user request is "resume" or "continue" or "try again", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is.
+
+Take your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided.
+
+You MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.
+
+# Workflow
+
+1. Understand the problem deeply. Carefully read the issue and think critically about what is required.
+2. Investigate the codebase. Explore relevant files, search for key functions, and gather context.
+3. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using standard markdown format. Make sure you wrap the todo list in triple backticks so that it is formatted correctly.
+4. Implement the fix incrementally. Make small, testable code changes.
+5. Debug as needed. Use debugging techniques to isolate and resolve issues.
+6. Test frequently. Run tests after each change to verify correctness.
+7. Iterate until the root cause is fixed and all tests pass.
+8. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.
+
+Refer to the detailed sections below for more information on each step.
+
+## 1. Deeply Understand the Problem
+Carefully read the issue and think hard about a plan to solve it before coding.
+
+## 2. Codebase Investigation
+- Explore relevant files and directories.
+- Search for key functions, classes, or variables related to the issue.
+- Read and understand relevant code snippets.
+- Identify the root cause of the problem.
+- Validate and update your understanding continuously as you gather more context.
+
+## 3. Fetch Provided URLs
+- If the user provides a URL, use the `functions.fetch_webpage` tool to retrieve the content of the provided URL.
+- After fetching, review the content returned by the fetch tool.
+- If you find any additional URLs or links that are relevant, use the `fetch_webpage` tool again to retrieve those links.
+- Recursively gather all relevant information by fetching additional links until you have all the information you need.
+
+## 4. Develop a Detailed Plan
+- Outline a specific, simple, and verifiable sequence of steps to fix the problem.
+- Create a todo list in markdown format to track your progress.
+- Each time you complete a step, check it off using `[x]` syntax.
+- Each time you check off a step, display the updated todo list to the user.
+- Make sure that you ACTUALLY continue on to the next step after checkin off a step instead of ending your turn and asking the user what they want to do next.
+
+## 5. Making Code Changes
+- Before editing, always read the relevant file contents or section to ensure complete context.
+- Always read 2000 lines of code at a time to ensure you have enough context.
+- If a patch is not applied correctly, attempt to reapply it.
+- Make small, testable, incremental changes that logically follow from your investigation and plan.
+
+## 6. Debugging
+- Make code changes only if you have high confidence they can solve the problem
+- When debugging, try to determine the root cause rather than addressing symptoms
+- Debug for as long as needed to identify the root cause and identify a fix
+- Use the #problems tool to check for any problems in the code
+- Use print statements, logs, or temporary code to inspect program state, including descriptive statements or error messages to understand what's happening
+- To test hypotheses, you can also add test statements or functions
+- Revisit your assumptions if unexpected behavior occurs.
+
+# Fetch Webpage
+Use the `fetch_webpage` tool when the user provides a URL. Follow these steps exactly.
+
+1. Use the `fetch_webpage` tool to retrieve the content of the provided URL.
+2. After fetching, review the content returned by the fetch tool.
+3. If you find any additional URLs or links that are relevant, use the `fetch_webpage` tool again to retrieve those links.
+4. Go back to step 2 and repeat until you have all the information you need.
+
+IMPORTANT: Recursively fetching links is crucial. You are not allowed skip this step, as it ensures you have all the necessary context to complete the task.
+
+# How to create a Todo List
+Use the following format to create a todo list:
+```markdown
+- [ ] Step 1: Description of the first step
+- [ ] Step 2: Description of the second step
+- [ ] Step 3: Description of the third step
+```
+
+Do not ever use HTML tags or any other formatting for the todo list, as it will not be rendered correctly. Always use the markdown format shown above.
+
+# Creating Files
+Each time you are going to create a file, use a single concise sentence inform the user of what you are creating and why.
+
+# Reading Files
+- Read 2000 lines of code at a time to ensure that you have enough context.
+- Each time you read a file, use a single concise sentence to inform the user of what you are reading and why.
\ No newline at end of file
dots/.config/aichat/roles/codereview.md
@@ -0,0 +1,1 @@
+Review the following code and report any obvious issues. Be brief and direct—no nitpicking, just major flaws or inefficiencies.
dots/.config/aichat/roles/findbug.md
@@ -0,0 +1,7 @@
+This is is a list of files from a git change, the list of the changed have the
+original file prior to the changes and the diff with the changes. Can you
+careful analyze the changes and find if there is bug? or spelling mistakes or improvement of code to make it more idiomatic?
+
+Here is the list of files:
+
+__INPUT__
dots/.config/aichat/roles/gitbranch.md
@@ -0,0 +1,6 @@
+can you suggest a git branch name out of this diff, just output the branch name
+nothing else. Do not add slash into the branch name or the type like
+feature/bugfix etc. Make sure to separate words with hyphens.
+
+if you see a SRVKP (jira ticket) always specify it branch name capitalized like
+SRVKP at the beginning.
dots/.config/aichat/roles/gitcommit.md
@@ -0,0 +1,39 @@
+You are to generate a commit message based on the provided file list and diffs.
+Wait until I say **END OF INPUT** before responding.
+
+Format your response as follows:
+
+<type>: <subject>
+
+<body>
+
+**Rules:**
+
+* `type`: One of `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `chore`.
+* Subject:
+ * 50–70 characters.
+ * Capitalize only the first letter.
+ * Imperative mood.
+ * No ending period.
+ * No “and”.
+* Body:
+ * Cohesive long phrase or paragraph unless multiple points are needed.
+ * Use bullet points only if necessary for clarity.
+ * Past tense.
+ * State **what** and **why** only (no “how”).
+ * Skip obvious reasons.
+ * Skip really minor changes that are not important to mention.
+ * Avoid phrases like "for better visual clarity" unless essential.
+ * Wrap at 72 characters.
+ * Don't say obvious things like "This streamlined" avoid it.
+* For small changes, use `fix`.
+* Insert a blank line between subject and body.
+* Follow Conventional Commits 1.0.0.
+
+**Output:** Commit message only — no extra text.
+
+**Input:**
+
+```
+__INPUT__
+```
dots/.config/aichat/roles/jira-release-note.md
@@ -0,0 +1,1 @@
+Create a 3 lines release note for a jira ticket. The note should be concise and highlight the key changes or fixes made in the ticket. This should use red hat documentation style.
dots/.config/aichat/roles/jira.md
@@ -0,0 +1,71 @@
+---
+mode: 'ask'
+---
+I am going to copy you a jira template, and I will be copying to you a bunch of
+discussions and context after that, can you help me make the jira issue and
+provide a title for it?
+
+### IMPORTANT, make sure to follow these guidelines:
+
+- Make sure to don't add implementation details, just the high level
+context. We want to keep the implementation details for the engineers to figure.
+- Try to add link if you see something that can be linked in the jira issue.
+- Always output as Jira markdown formatting.
+- Make it easy to copy and paste to the jira input box.
+- Do not mention customer names. Just reference them as "customer".
+
+### Assistant instructions (use this when I paste template + context)
+
+- I will paste a Jira template followed by discussion/context. Produce:
+ - A concise Jira issue body that fills the provided template (Jira markdown).
+ - A short, descriptive issue title (one line).
+- Keep the issue high-level — do NOT add implementation details or design steps. Engineers will own those.
+- Prefer including links when available (use full URLs or JIRA-KEY format).
+- Use clear, testable Acceptance Criteria (Given / When / Then or numbered checklist).
+- Always add blockquote ```jira-markup at the start and finish ``` at the start and end of the output.
+- Output only Jira-compatible markdown (no code fences or extra commentary) and format so it’s copy-paste ready into the Jira input box.
+
+### Jira Template
+
+```jira-markup
+
+h1. Story (Required)
+
+As a <PERSONA> trying to <ACTION> I want <THIS OUTCOME>
+
+_<Describes high level purpose and goal for this story. Answers the questions: Who is impacted, what is it and why do we need it? How does it improve the customer’s experience?>_
+
+h2. *Background (Required)*
+
+_<Describes the context or background related to this story>_
+
+h2. *Out of scope*
+
+_<Defines what is not included in this story>_
+
+h2. *Approach (Required)*
+
+_<Description of the general technical path on how to achieve the goal of the story. Include details like json schema, class definitions>_
+
+h2. *Dependencies*
+
+_<Describes what this story depends on. Dependent Stories and EPICs should be linked to the story.>_
+
+h2. *Acceptance Criteria (Mandatory)*
+
+_<Describe edge cases to consider when implementing the story and defining tests>_
+_<Provides a required and minimum list of acceptance tests for this story. More is expected as the engineer implements this story>_
+
+h1. *INVEST Checklist*
+
+ Dependencies identified
+
+ Blockers noted and expected delivery timelines set
+
+ Design is implementable
+
+ Acceptance criteria agreed upon
+
+ Story estimated
+
+```
dots/.config/aichat/roles/jira.ticket.prompt.md
@@ -0,0 +1,1 @@
+jira.md
\ No newline at end of file
dots/.config/aichat/roles/jirabug.md
@@ -0,0 +1,25 @@
+I am going to copy you a jira template, and I will be copying to you a bunch of
+discussions and context after that, can you help me make the jira issue and
+provide a title for it? Make sure to output as jira formatting and make it easy
+to copy and paste directly on the jira textbox, so no specific markdown
+
+Jira Template for a bug, using jira formtatting:
+
+h3. *Description of problem:*
+
+Workaround
+h3. *Prerequisites (if any, like setup, operators/versions):*
+h3. *Steps to Reproduce*
+
+# <steps>
+
+h3. *Actual results:*
+h3. *Expected results:*
+h3. *Reproducibility (Always/Intermittent/Only Once):*
+h3. *Acceptance criteria:*
+
+*Definition of Done:*
+h3. *Build Details:*
+h3. *Additional info (Such as Logs, Screenshots, etc):*
+
+h3. *
dots/.config/aichat/roles/markdown.md
@@ -0,0 +1,18 @@
+You are a technical writer at IBM, tasked with refining an engineer's draft documentation for OpenShift. Your responsibilities include:
+
+1. Correcting spelling, grammar, punctuation, and formatting errors.
+2. Rephrasing content for clarity, conciseness, and fluency while maintaining technical accuracy.
+3. Ensuring the tone and style align with IBM's professional documentation standards.
+4. Retaining any markdown formatting (e.g., headers, lists, inline code) and enhancing its usage to improve readability and structure.
+5. Ensuring the content conforms to **Markdownlint rules**. The most common rules include:
+ - Use a single `#` for the main heading and avoid skipping heading levels. (except keep metadata)
+ - Ensure line lengths do not exceed 80 characters (where possible).
+ - Use consistent spacing after list markers (e.g., `-`, `*`, `1.`).
+ - Include blank lines before and after headers, code blocks, and lists.
+ - Avoid trailing spaces at the end of lines.
+ - Use fenced code blocks (``` or ~~~) for code snippets.
+ - Use unordered lists consistently (e.g., don't mix `-` and `*`).
+ - Ensure links are formatted correctly `[text](url)` and avoid duplicate link definitions.
+ - Include alt text for images: ``.
+6. Do not add initial ```markdown and end with a``` markers
+7. Do not remove the initial markdown metadata
dots/.config/aichat/roles/release.md
@@ -0,0 +1,11 @@
+Here is the output of my releases changes, can you make a list of all notable
+changes and categorize it nicely between features/bugs/misc with emojis output
+as markdown and a one liner of the change?
+
+Make sure to link the commit url to a prefix with
+<https://github.com/openshift-pipelines/pipelines-as-code/commit/> at the end
+of each changes. Add a jira link like
+[SRVKP-XXX](https://issues.redhat.com/browse/SRKVP-XXX) for each change if there is
+one specified in the commit message.
+
+__INPUT__
dots/.config/aichat/roles/rewrite.md
@@ -0,0 +1,5 @@
+Rewrite this text to be better english or french if written in french, more concise, and more engaging. Maintain the original meaning and context and tone. Make sure to answer in the original language of the text.
+
+Only output the rewritten text, do not include any additional comments or explanations or any options.
+
+__INPUT__
dots/.config/aichat/roles/spell.md
@@ -0,0 +1,11 @@
+Vous êtes un modèle conçu pour corriger uniquement les fautes de français dans un
+texte. Répondez en renvoyant exclusivement le texte corrigé, sans
+explications, annotations, ou autre contenu.
+
+Si vous ne pouvez pas corriger le texte, renvoyez-le tel quel, inchangé.
+Si le texte est en Markdown, conservez la mise en forme à tout prix.
+Si le texte est en anglais, renvoyez la réponse en anglais.
+
+Voici le texte à corriger :
+
+__INPUT__
dots/.config/aichat/config.yaml.in
@@ -0,0 +1,50 @@
+model: gemini:gemini-2.5-flash-lite-preview-09-2025
+wrap: 150
+save_session: true
+clients:
+ - type: gemini
+ name: gemini
+ api_base: https://generativelanguage.googleapis.com/v1beta
+ api_key: "passage::ai/gemini/api_key"
+ patch:
+ chat_completions:
+ ".*":
+ body:
+ safetySettings:
+ - category: HARM_CATEGORY_HARASSMENT
+ threshold: BLOCK_NONE
+ - category: HARM_CATEGORY_HATE_SPEECH
+ threshold: BLOCK_NONE
+ - category: HARM_CATEGORY_SEXUALLY_EXPLICIT
+ threshold: BLOCK_NONE
+ - category: HARM_CATEGORY_DANGEROUS_CONTENT
+ threshold: BLOCK_NONE
+
+ - type: openai-compatible
+ name: ollama
+ api_base: http://127.0.0.1:11434/v1
+ api_key: null
+
+ - type: openai-compatible
+ name: groq
+ api_base: https://api.groq.com/openai/v1
+ api_key: "passage::ai/groq/wakasu"
+
+ # See https://platform.deepseek.com/api-docs/
+ - type: openai-compatible
+ name: deepseek
+ api_base: https://api.deepseek.com
+ api_key: "passage::ai/deepseek/api_key"
+
+ - type: openai-compatible
+ name: openrouter
+ api_base: https://openrouter.ai/api/v1
+ api_key: "passage::ai/openroute/api_key"
+
+ - type: openai-compatible
+ name: redhat-maas-deepseek
+ api_base: https://deepseek-r1-distill-qwen-14b-maas-apicast-production.apps.prod.rhoai.rh-aiservices-bu.com/v1
+ api_key: "passage::redhat/maas.deepseek.distill.api.key"
+ models:
+ - name: deepseek-r1-distill-qwen-14b
+ description: DeepSeek R1 Distill Qwen 14B
dots/.config/aichat/genconf.py
@@ -0,0 +1,257 @@
+#!/usr/bin/env -S uv run --script
+# /// script
+# dependencies = [
+# "requests",
+# "PyYAML",
+# "google-generativeai",
+# ]
+# ///
+
+import os
+import os.path
+import subprocess
+import socket
+import sys
+from typing import Any, Dict, List, Optional
+
+import requests
+import yaml # pip install pyyaml types-pyyaml
+import urllib.parse as urlparse
+import google.generativeai as genai
+
+
+def debug(msg: str):
+ print(f"[DEBUG] {msg}", file=sys.stderr)
+
+
+def check_running(api_base, timeout=0.5) -> bool:
+ """Quickly check if Ollama is accessible at the given host and port."""
+ url = urlparse.urlparse(api_base)
+ port = url.port or (80 if url.scheme == "http" else 443)
+ debug(f"Checking if {url.hostname}:{port} is running (api_base={api_base})")
+ try:
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sock.settimeout(timeout)
+ result = sock.connect_ex((url.hostname, port))
+ sock.close()
+ debug(f"Socket connect_ex result for {url.hostname}:{port}: {result}")
+ return result == 0
+ except Exception as e:
+ debug(f"Exception in check_running: {e}")
+ raise e
+
+
+def load_config(config_path: str) -> Dict[str, Any]:
+ debug(f"Loading config from {config_path}")
+ with open(config_path, "r") as file:
+ config = yaml.safe_load(file)
+ debug(f"Loaded config: {config}")
+ return config
+
+
+def get_models(api_base: str, api_key_config: str | None) -> List[Dict[str, str]]:
+ """Query the models endpoint and return a list of model data"""
+ debug(
+ f"get_models called with api_base={api_base}, api_key_config={api_key_config}"
+ )
+ actual_api_key = None
+ if api_key_config:
+ if api_key_config.startswith("passage::"):
+ passage_path = api_key_config.split("::", 1)[1]
+ debug(f"Retrieving API key from passage at {passage_path}")
+ actual_api_key = get_passageword(passage_path)
+ if not actual_api_key:
+ print(
+ f"Could not retrieve API key from passage for path: {passage_path}",
+ file=sys.stderr,
+ )
+ debug(f"Failed to retrieve API key from passage for {passage_path}")
+ # Decide how to handle failure: skip, return empty, etc.
+ # Here we'll proceed without a key, which might fail later.
+ else:
+ actual_api_key = api_key_config # Use the key directly if not a passage path
+ debug("Using API key directly from config")
+
+ headers = {}
+ if actual_api_key:
+ headers["Authorization"] = f"Bearer {actual_api_key}"
+ debug("Authorization header set")
+
+ # Ensure the URL is properly formatted
+ if not api_base.endswith("/"):
+ api_base = api_base + "/"
+ debug(f"api_base adjusted to {api_base}")
+
+ models_url = f"{api_base}models"
+ debug(f"Querying models endpoint: {models_url}")
+
+ try:
+ response = requests.get(models_url, headers=headers, timeout=10)
+ debug(f"HTTP GET {models_url} status_code={response.status_code}")
+ response.raise_for_status()
+ data = response.json()
+ debug(f"Response JSON: {data}")
+
+ # Extract models from response
+ models = data.get("data", [])
+ debug(f"Extracted models: {models}")
+ return [
+ {"name": model.get("id"), "description": model.get("id")}
+ for model in models
+ ]
+ except Exception as e:
+ print(f"Error querying {api_base}: {str(e)}", file=sys.stderr)
+ debug(f"Exception in get_models: {e}")
+ return []
+
+
+def get_gemini_models(api_key: Optional[str]) -> List[Dict[str, str]]:
+ """Query Google's Gemini API and return a list of available models"""
+ debug(f"get_gemini_models called with api_key={'***' if api_key else None}")
+ if not api_key:
+ print("Error: API key is required for Google Gemini API", file=sys.stderr)
+ debug("No API key provided to get_gemini_models")
+ return []
+
+ try:
+ # Configure the Gemini API with the provided key
+ debug("Configuring genai with provided API key")
+ genai.configure(api_key=api_key)
+
+ # Get list of available models
+ debug("Listing models from genai")
+ models_list = genai.list_models()
+ debug(f"Models list: {models_list}")
+
+ # Filter for Gemini models
+ gemini_models = [
+ {"name": model.name.split("/")[-1], "description": model.description}
+ for model in models_list
+ if "gemini" in model.name.lower()
+ ]
+ debug(f"Filtered Gemini models: {gemini_models}")
+
+ return gemini_models
+ except Exception as e:
+ print(f"Error querying Google Gemini API: {str(e)}", file=sys.stderr)
+ debug(f"Exception in get_gemini_models: {e}")
+ return []
+
+
+def get_passageword(passage_path: str) -> str | None:
+ """Retrieve passageword from passage using the given path."""
+ debug(f"get_passageword called for passage_path={passage_path}")
+ try:
+ result = subprocess.run(
+ ["passage", "show", passage_path], capture_output=True, text=True, check=True
+ )
+ # Return the first line of the output, stripping newline
+ passageword = result.stdout.splitlines()[0]
+ debug(f"Passageword retrieved from passage for {passage_path}")
+ return passageword
+ except FileNotFoundError:
+ print(
+ "Error: 'passage' command not found. Is passage installed and in your PATH?",
+ file=sys.stderr,
+ )
+ debug("'passage' command not found")
+ return None
+ except subprocess.CalledProcessError as e:
+ print(f"Error running passage show {passage_path}: {e.stderr}", file=sys.stderr)
+ debug(f"subprocess.CalledProcessError in get_passageword: {e}")
+ return None
+ except IndexError:
+ print(f"Error: 'passage show {passage_path}' returned empty output.", file=sys.stderr)
+ debug(f"IndexError: passage show {passage_path} returned empty output")
+ return None
+
+
+def main():
+ # Support reading from script directory or ~/.config/aichat/
+ script_dir = os.path.dirname(os.path.abspath(__file__))
+ config_path = os.path.join(script_dir, "config.yaml.in")
+
+ if not os.path.exists(config_path):
+ config_path = os.path.expanduser("~/.config/aichat/config.yaml.in")
+
+ debug(f"main: config_path={config_path}")
+ config_data = load_config(config_path)
+
+ if "clients" in config_data:
+ updated_clients = []
+ debug(f"main: found {len(config_data.get('clients', []))} clients")
+ for client in config_data.get("clients", []):
+ # Make a copy to avoid modifying the original dict during iteration if needed elsewhere
+ updated_client = client.copy()
+ debug(f"Processing client: {updated_client}")
+
+ actual_api_key = None
+ api_key_config = updated_client.get("api_key")
+ if api_key_config and api_key_config.startswith("passage::"):
+ passage_path = api_key_config.split("::", 1)[1]
+ debug(f"main: retrieving api_key from passage for {passage_path}")
+ actual_api_key = get_passageword(passage_path)
+ else:
+ actual_api_key = api_key_config
+ updated_client["api_key"] = actual_api_key
+ debug("main: actual_api_key set for client")
+
+ # For OpenAI-compatible clients, query and potentially add models
+ if updated_client.get("type") == "openai-compatible":
+ # Check if models are NOT already defined in config or are empty
+ if not updated_client.get("models"):
+ api_base = updated_client.get("api_base")
+ api_key = updated_client.get("api_key")
+ debug(
+ f"main: openai-compatible client, api_base={api_base}, api_key={'***' if api_key else None}"
+ )
+
+ # Skip ollama explicitly if needed, or handle based on your logic
+ if api_base:
+ if not check_running(api_base):
+ debug(f"main: {api_base} not running, skipping client")
+ continue
+ # Try to fetch models from API
+ fetched_models = get_models(api_base, api_key)
+ if fetched_models:
+ updated_client["models"] = fetched_models
+ debug("main: models fetched and set for client")
+ else:
+ # Keep models empty/undefined or add an empty list
+ updated_client["models"] = []
+ debug("main: no models fetched, set empty list")
+ else:
+ # Handle cases where type is openai-compatible but no api_base
+ updated_client["models"] = []
+ debug(
+ "main: openai-compatible client with no api_base, set empty models"
+ )
+
+ # For Google Gemini clients, query and potentially add models
+ elif updated_client.get("type") == "gemini":
+ # Check if models are NOT already defined in config or are empty
+ if not updated_client.get("models"):
+ api_key = updated_client.get("api_key")
+ debug(f"main: gemini client, api_key={'***' if api_key else None}")
+ fetched_models = get_gemini_models(api_key)
+ if fetched_models:
+ updated_client["models"] = fetched_models
+ debug("main: gemini models fetched and set for client")
+ else:
+ updated_client["models"] = []
+ debug("main: no gemini models fetched, set empty list")
+
+ updated_clients.append(updated_client)
+ debug("main: client processed and added to updated_clients")
+
+ # Replace the original clients list with the updated one
+ config_data["clients"] = updated_clients
+ debug("main: updated_clients set in config_data")
+
+ # Print the entire (potentially updated) configuration as YAML
+ debug("main: dumping config_data as YAML")
+ print(yaml.dump(config_data, default_flow_style=False, sort_keys=False))
+
+
+if __name__ == "__main__":
+ main()
dots/Makefile
@@ -39,6 +39,11 @@ ntfy-scripts : ~/.config/ntfy/handle-notification.sh ~/.config/ntfy/acknowledge-
all += xmpp-research-bot
xmpp-research-bot : ~/.config/xmpp-research-bot/commands.yaml
+all += aichat-config aichat-genconf aichat-roles
+aichat-config : ~/.config/aichat/config.yaml
+aichat-genconf : ~/.config/aichat/genconf.py
+aichat-roles : ~/.config/aichat/roles
+
# Backward compatibility: symlink ~/.claude to ~/.config/claude
~/.claude : force
@echo "🔗 Creating backward compatibility symlink: ~/.claude -> ~/.config/claude"
@@ -50,6 +55,11 @@ xmpp-research-bot : ~/.config/xmpp-research-bot/commands.yaml
@echo "⚙️ Generating $$@ from template with passage secrets"
@$(dotfiles)/.config/ntfy/ntfy-update-config
+# Generate aichat config.yaml from template with dynamic model fetching
+~/.config/aichat/config.yaml : $(dotfiles)/.config/aichat/config.yaml.in $(dotfiles)/.config/aichat/genconf.py force
+ @echo "⚙️ Generating ~/.config/aichat/config.yaml with dynamic models and passage secrets"
+ @$(dotfiles)/.config/aichat/genconf.py > ~/.config/aichat/config.yaml 2>/dev/null
+
all : $(all)
@echo "✅ All dotfiles installed!"
home/common/dev/ai.nix
@@ -30,20 +30,6 @@
# amp-cli
];
- xdg.configFile."aichat/config.yaml.in".source = ./aichat.yaml;
- xdg.configFile."aichat/models-override.yaml".source = ./aichat-models-override.yaml;
- xdg.configFile."aichat/genconf.py" = {
- source = ./genconf.py;
- executable = true;
- };
- # xdg.configFile."aichat/update-config" = {
- # source = ./aichat-update-config;
- # executable = true;
- # };
- # home.activation = {
- # # linkGeneration writeBoundary
- # aichat-configuration = lib.hm.dag.entryAfter [ "linkGeneration" ] ''
- # /home/vincent/.config/aichat/genconf.py
- # '';
- # };
+ # aichat configuration is now managed in dots/.config/aichat/
+ # See dots/Makefile for config.yaml generation from template
}