«`html
Building a Secure and Memory-Enabled Cipher Workflow for AI Agents with Dynamic LLM Selection and API Integration
This tutorial provides a step-by-step guide to creating a compact yet fully functional Cipher-based workflow. We will first address the secure capture of the Gemini API key in the Colab UI without exposing it in the code. We will then implement a dynamic LLM selection function that automatically switches between OpenAI, Gemini, or Anthropic based on the available API key. The setup phase ensures that Node.js and the Cipher CLI are installed. Afterward, we programmatically generate a cipher.yml configuration to enable a memory agent with long-term recall. We will also create helper functions to execute Cipher commands directly from Python and store key project decisions as persistent memories, which can be retrieved on demand.
Step 1: Securing API Key Input
We securely capture our Gemini API key using the getpass
module, ensuring it remains hidden in the Colab UI:
import os, getpass
os.environ["GEMINI_API_KEY"] = getpass.getpass("Enter your Gemini API key: ").strip()
Step 2: Dynamic LLM Selection
The choose_llm
function checks our environment variables and automatically selects the appropriate LLM provider, model, and API key based on what is available:
def choose_llm():
if os.getenv("OPENAI_API_KEY"):
return "openai", "gpt-4o-mini", "OPENAI_API_KEY"
if os.getenv("GEMINI_API_KEY"):
return "gemini", "gemini-2.5-flash", "GEMINI_API_KEY"
if os.getenv("ANTHROPIC_API_KEY"):
return "anthropic", "claude-3-5-haiku-20241022", "ANTHROPIC_API_KEY"
raise RuntimeError("Set one API key before running.")
Step 3: Helper Function for Command Execution
We implement the run
function that executes shell commands, providing visibility into both standard output and error:
def run(cmd, check=True, env=None):
print("▸", cmd)
p = subprocess.run(cmd, shell=True, text=True, capture_output=True, env=env)
if p.stdout: print(p.stdout)
if p.stderr: print(p.stderr)
if check and p.returncode != 0:
raise RuntimeError(f"Command failed: {cmd}")
return p
Step 4: Ensuring Environment Setup
We define ensure_node_and_cipher
to install Node.js, npm, and the Cipher CLI globally:
def ensure_node_and_cipher():
run("sudo apt-get update -y && sudo apt-get install -y nodejs npm", check=False)
run("npm install -g @byterover/cipher")
Step 5: Generating Configuration File
The write_cipher_yml
function creates a cipher.yml configuration file for the memory agent:
def write_cipher_yml(workdir, provider, model, key_env):
cfg = """
llm:
provider: {provider}
model: {model}
apiKey: ${key_env}
systemPrompt:
enabled: true
content: |
You are an AI programming assistant with long-term memory of prior decisions.
embedding:
disabled: true
mcpServers:
filesystem:
type: stdio
command: npx
args: ['-y','@modelcontextprotocol/server-filesystem','.']
""".format(provider=provider, model=model, key_env=key_env)
(workdir / "memAgent").mkdir(parents=True, exist_ok=True)
(workdir / "memAgent" / "cipher.yml").write_text(cfg.strip() + "\n")
Step 6: Executing Cipher Commands
We create the cipher_once
function to run a single Cipher CLI command:
def cipher_once(text, env=None, cwd=None):
cmd = f'cipher {shlex.quote(text)}'
p = subprocess.run(cmd, shell=True, text=True, capture_output=True, env=env, cwd=cwd)
print("Cipher says:\n", p.stdout or p.stderr)
return p.stdout.strip() or p.stderr.strip()
Step 7: Starting the API Server
The start_api
function initializes the Cipher in API mode:
def start_api(env, cwd):
proc = subprocess.Popen("cipher --mode api", shell=True, env=env, cwd=cwd,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
for _ in range(30):
try:
r = requests.get("http://127.0.0.1:3000/health", timeout=2)
if r.ok:
print("API /health:", r.text)
break
except: pass
time.sleep(1)
return proc
Step 8: Main Function Execution
The main
function orchestrates all components:
def main():
provider, model, key_env = choose_llm()
ensure_node_and_cipher()
workdir = pathlib.Path(tempfile.mkdtemp(prefix="cipher_demo_"))
write_cipher_yml(workdir, provider, model, key_env)
env = os.environ.copy()
cipher_once("Store decision: use pydantic for config validation; pytest fixtures for testing.", env, str(workdir))
cipher_once("Remember: follow conventional commits; enforce black + isort in CI.", env, str(workdir))
cipher_once("What did we standardize for config validation and Python formatting?", env, str(workdir))
api_proc = start_api(env, str(workdir))
time.sleep(3)
api_proc.terminate()
if __name__ == "__main__":
main()
Conclusion
This implementation creates a working Cipher environment that securely manages API keys, selects the right LLM provider automatically, and configures a memory-enabled agent through Python automation. The workflow encompasses decision logging, memory retrieval, and a live API endpoint, making it suitable for AI-assisted development pipelines.
For further resources, please check our GitHub Page for tutorials, codes, and notebooks. You can also follow us on Twitter and join our ML SubReddit for more community-driven discussions.
Star us on GitHub
Join our ML Subreddit
Sponsor us
«`