agent-factory: generate agent auto-retrieve-files-from-a-reposito
This commit is contained in:
1
.image-version
Normal file
1
.image-version
Normal file
@@ -0,0 +1 @@
|
|||||||
|
1.0.0
|
||||||
25
Dockerfile
Normal file
25
Dockerfile
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
FROM python:3.12-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
curl \
|
||||||
|
ca-certificates \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
COPY app/ ./app/
|
||||||
|
|
||||||
|
RUN useradd -m -u 1001 appuser && \
|
||||||
|
chown -R appuser:appuser /app
|
||||||
|
|
||||||
|
USER appuser
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
|
||||||
|
CMD curl -f http://localhost:8080/health || exit 1
|
||||||
|
|
||||||
|
CMD ["uvicorn", "app.agent:app", "--host", "0.0.0.0", "--port", "8080"]
|
||||||
0
app/__init__.py
Normal file
0
app/__init__.py
Normal file
148
app/agent.py
Normal file
148
app/agent.py
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
"""
|
||||||
|
AutoRetrieveFilesFromAReposito Agent — auto-generated by Agent Factory.
|
||||||
|
"""
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
import click
|
||||||
|
import httpx
|
||||||
|
import uvicorn
|
||||||
|
from contextlib import asynccontextmanager
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from langchain_core.rate_limiters import InMemoryRateLimiter
|
||||||
|
from langchain_openai import AzureChatOpenAI
|
||||||
|
|
||||||
|
from starlette.applications import Starlette
|
||||||
|
from starlette.requests import Request
|
||||||
|
from starlette.responses import JSONResponse
|
||||||
|
from starlette.routing import Route
|
||||||
|
|
||||||
|
from app.config import (
|
||||||
|
AGENT_SELF_URL,
|
||||||
|
AZURE_OPENAI_API_KEY,
|
||||||
|
AZURE_OPENAI_API_VERSION,
|
||||||
|
AZURE_OPENAI_DEPLOYMENT,
|
||||||
|
AZURE_OPENAI_ENDPOINT,
|
||||||
|
LOG_LEVEL,
|
||||||
|
REGISTRY_URL,
|
||||||
|
)
|
||||||
|
from app.skills import AGENT_CONFIG, AUTO_RETRIEVE_FILES_FROM_A_REPOSITO_SKILLS
|
||||||
|
from app.workflows.auto_retrieve_files_from_a_reposito_workflow import create_auto_retrieve_files_from_a_reposito_workflow
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
# ── Logging ──────────────────────────────────────────────────────────────
|
||||||
|
logging.basicConfig(
|
||||||
|
level=getattr(logging, LOG_LEVEL.upper(), logging.INFO),
|
||||||
|
format="%(asctime)s %(name)s %(levelname)s %(message)s",
|
||||||
|
)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# ── LLM ──────────────────────────────────────────────────────────────────
|
||||||
|
rate_limiter = InMemoryRateLimiter(
|
||||||
|
requests_per_second=10 / 60,
|
||||||
|
check_every_n_seconds=0.1,
|
||||||
|
max_bucket_size=10,
|
||||||
|
)
|
||||||
|
|
||||||
|
llm = AzureChatOpenAI(
|
||||||
|
temperature=0,
|
||||||
|
azure_deployment=AZURE_OPENAI_DEPLOYMENT,
|
||||||
|
api_version=AZURE_OPENAI_API_VERSION,
|
||||||
|
azure_endpoint=AZURE_OPENAI_ENDPOINT or "",
|
||||||
|
api_key=AZURE_OPENAI_API_KEY or "",
|
||||||
|
max_retries=5,
|
||||||
|
timeout=120,
|
||||||
|
rate_limiter=rate_limiter,
|
||||||
|
)
|
||||||
|
|
||||||
|
workflow = create_auto_retrieve_files_from_a_reposito_workflow(llm)
|
||||||
|
|
||||||
|
|
||||||
|
# ── Endpoints ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
async def health_check(request: Request) -> JSONResponse:
|
||||||
|
return JSONResponse({"status": "healthy", "agent": 'AutoRetrieveFilesFromAReposito'})
|
||||||
|
|
||||||
|
|
||||||
|
async def agent_manifest(request: Request) -> JSONResponse:
|
||||||
|
"""GET /.well-known/agent.json"""
|
||||||
|
return JSONResponse({
|
||||||
|
"name": AGENT_CONFIG["name"],
|
||||||
|
"version": AGENT_CONFIG["version"],
|
||||||
|
"description": AGENT_CONFIG["description"],
|
||||||
|
"url": "/",
|
||||||
|
"skills": [
|
||||||
|
{
|
||||||
|
"id": s.id,
|
||||||
|
"name": s.name,
|
||||||
|
"description": s.description,
|
||||||
|
"tags": s.tags,
|
||||||
|
"inputSchema": AGENT_CONFIG.get("input_schema"),
|
||||||
|
"outputSchema": AGENT_CONFIG.get("output_schema"),
|
||||||
|
} for s in AUTO_RETRIEVE_FILES_FROM_A_REPOSITO_SKILLS
|
||||||
|
],
|
||||||
|
"capabilities": AGENT_CONFIG["capabilities"],
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
async def process_endpoint(request: Request) -> JSONResponse:
|
||||||
|
"""POST /process — run the agent workflow."""
|
||||||
|
try:
|
||||||
|
body = await request.json()
|
||||||
|
result = await workflow.ainvoke(body)
|
||||||
|
return JSONResponse(result)
|
||||||
|
except Exception as exc:
|
||||||
|
logger.error("Processing failed: %s", exc, exc_info=True)
|
||||||
|
return JSONResponse({"error": str(exc)}, status_code=500)
|
||||||
|
|
||||||
|
|
||||||
|
# ── Self-registration ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
async def _register_with_registry():
|
||||||
|
if not REGISTRY_URL:
|
||||||
|
logger.info("REGISTRY_URL not set — skipping self-registration")
|
||||||
|
return
|
||||||
|
await asyncio.sleep(2)
|
||||||
|
url = f"{REGISTRY_URL.rstrip('/')}/agents/register-url"
|
||||||
|
for attempt in range(3):
|
||||||
|
try:
|
||||||
|
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||||
|
resp = await client.post(url, json={"endpoint": AGENT_SELF_URL})
|
||||||
|
if resp.status_code in (200, 201):
|
||||||
|
logger.info("Self-registered with agent-registry at %s", REGISTRY_URL)
|
||||||
|
return
|
||||||
|
logger.warning("Registration attempt %d: HTTP %d", attempt + 1, resp.status_code)
|
||||||
|
except Exception as exc:
|
||||||
|
logger.warning("Registration attempt %d failed: %s", attempt + 1, exc)
|
||||||
|
await asyncio.sleep(5)
|
||||||
|
logger.error("Failed to self-register after 3 attempts")
|
||||||
|
|
||||||
|
|
||||||
|
@asynccontextmanager
|
||||||
|
async def lifespan(app):
|
||||||
|
task = asyncio.create_task(_register_with_registry())
|
||||||
|
yield
|
||||||
|
task.cancel()
|
||||||
|
|
||||||
|
|
||||||
|
app = Starlette(
|
||||||
|
routes=[
|
||||||
|
Route("/health", methods=["GET"], endpoint=health_check),
|
||||||
|
Route("/.well-known/agent.json", methods=["GET"], endpoint=agent_manifest),
|
||||||
|
Route("/process", methods=["POST"], endpoint=process_endpoint),
|
||||||
|
],
|
||||||
|
lifespan=lifespan,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
@click.option("--host", default="0.0.0.0")
|
||||||
|
@click.option("--port", default=8080, type=int)
|
||||||
|
def main(host: str, port: int):
|
||||||
|
uvicorn.run(app, host=host, port=port, log_level=LOG_LEVEL.lower())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
21
app/config.py
Normal file
21
app/config.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
"""
|
||||||
|
Configuration for the AutoRetrieveFilesFromAReposito agent.
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
|
||||||
|
# ── Azure OpenAI ─────────────────────────────────────────────────────────
|
||||||
|
AZURE_OPENAI_ENDPOINT = os.getenv("AZURE_OPENAI_ENDPOINT")
|
||||||
|
AZURE_OPENAI_API_KEY = os.getenv("AZURE_OPENAI_API_KEY")
|
||||||
|
AZURE_OPENAI_API_VERSION = os.getenv("AZURE_OPENAI_API_VERSION", "2024-08-01-preview")
|
||||||
|
AZURE_OPENAI_DEPLOYMENT = os.getenv("AZURE_OPENAI_DEPLOYMENT", "gpt-4o")
|
||||||
|
|
||||||
|
# ── Agent Registry ───────────────────────────────────────────────────────
|
||||||
|
REGISTRY_URL = os.getenv(
|
||||||
|
"REGISTRY_URL", "http://agent-gateway.agents.svc.cluster.local"
|
||||||
|
)
|
||||||
|
AGENT_SELF_URL = os.getenv(
|
||||||
|
"AGENT_SELF_URL", "http://auto-retrieve-files-from-a-reposito.agents.svc.cluster.local"
|
||||||
|
)
|
||||||
|
|
||||||
|
# ── Logging ──────────────────────────────────────────────────────────────
|
||||||
|
LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO")
|
||||||
0
app/nodes/__init__.py
Normal file
0
app/nodes/__init__.py
Normal file
26
app/nodes/core_node.py
Normal file
26
app/nodes/core_node.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
async def process(state: dict) -> dict:
|
||||||
|
"""
|
||||||
|
This node retrieves files from a repository based on the provided URL and update scope.
|
||||||
|
It uses an LLM to analyze and extract relevant workflow files from the repository.
|
||||||
|
"""
|
||||||
|
from app.agent import llm
|
||||||
|
from langchain_core.messages import SystemMessage, HumanMessage
|
||||||
|
|
||||||
|
try:
|
||||||
|
repository_url = state.get("repository_url", "")
|
||||||
|
update_scope = state.get("update_scope", "")
|
||||||
|
|
||||||
|
if not repository_url or not update_scope:
|
||||||
|
raise ValueError("Both 'repository_url' and 'update_scope' must be provided.")
|
||||||
|
|
||||||
|
messages = [
|
||||||
|
SystemMessage(content="You are an assistant that retrieves workflow files from a repository."),
|
||||||
|
HumanMessage(content=f"Repository URL: {repository_url}\nUpdate Scope: {update_scope}")
|
||||||
|
]
|
||||||
|
|
||||||
|
response = await llm.ainvoke(messages)
|
||||||
|
workflow_files = response.content.splitlines() # Assuming the LLM returns file names as newline-separated strings.
|
||||||
|
|
||||||
|
return {"workflow_files": workflow_files, "phase": "complete"}
|
||||||
|
except Exception as exc:
|
||||||
|
return {"error": str(exc), "phase": "failed"}
|
||||||
29
app/skills.py
Normal file
29
app/skills.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
"""
|
||||||
|
A2A skill declarations for AutoRetrieveFilesFromAReposito.
|
||||||
|
"""
|
||||||
|
from a2a.types import AgentSkill
|
||||||
|
|
||||||
|
|
||||||
|
AUTO_RETRIEVE_FILES_FROM_A_REPOSITO_SKILLS = [
|
||||||
|
AgentSkill(
|
||||||
|
id="auto_retrieve_files_from_a_reposito_skill",
|
||||||
|
name="AutoRetrieveFilesFromAReposito",
|
||||||
|
description="Retrieve files from a repository",
|
||||||
|
tags=["auto-generated"],
|
||||||
|
examples=[],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
AGENT_CONFIG = {
|
||||||
|
"name": "AutoRetrieveFilesFromAReposito",
|
||||||
|
"description": "Fetch all Java workflow files from the Gitea repository",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"framework": "LangGraph + Starlette",
|
||||||
|
"capabilities": {
|
||||||
|
"streaming": False,
|
||||||
|
"async": True,
|
||||||
|
},
|
||||||
|
"input_schema": {"repository_url": "string", "update_scope": "string"},
|
||||||
|
"output_schema": {"workflow_files": "string[]"},
|
||||||
|
}
|
||||||
0
app/states/__init__.py
Normal file
0
app/states/__init__.py
Normal file
17
app/states/auto_retrieve_files_from_a_reposito_state.py
Normal file
17
app/states/auto_retrieve_files_from_a_reposito_state.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
"""
|
||||||
|
State definitions for AutoRetrieveFilesFromAReposito agent.
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
from typing import Any, Dict, List, Optional
|
||||||
|
from langgraph.graph import MessagesState
|
||||||
|
|
||||||
|
|
||||||
|
class AutoRetrieveFilesFromARepositoState(MessagesState):
|
||||||
|
"""Workflow state for AutoRetrieveFilesFromAReposito."""
|
||||||
|
# ── Input fields ─────────────────────────────────────────────────────
|
||||||
|
pass
|
||||||
|
# ── Output fields ────────────────────────────────────────────────────
|
||||||
|
pass
|
||||||
|
# ── Internal ─────────────────────────────────────────────────────────
|
||||||
|
error: Optional[str]
|
||||||
|
phase: str
|
||||||
0
app/workflows/__init__.py
Normal file
0
app/workflows/__init__.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
"""
|
||||||
|
LangGraph workflow for AutoRetrieveFilesFromAReposito agent.
|
||||||
|
"""
|
||||||
|
from langgraph.graph import StateGraph, END
|
||||||
|
|
||||||
|
from app.states.auto_retrieve_files_from_a_reposito_state import AutoRetrieveFilesFromARepositoState
|
||||||
|
from app.nodes.core_node import process
|
||||||
|
|
||||||
|
|
||||||
|
def create_auto_retrieve_files_from_a_reposito_workflow(llm):
|
||||||
|
"""Build and compile the AutoRetrieveFilesFromAReposito workflow graph."""
|
||||||
|
graph = StateGraph(AutoRetrieveFilesFromARepositoState)
|
||||||
|
|
||||||
|
graph.add_node("process", process)
|
||||||
|
|
||||||
|
graph.set_entry_point("process")
|
||||||
|
graph.add_edge("process", END)
|
||||||
|
|
||||||
|
return graph.compile()
|
||||||
35
catalog-info.yaml
Normal file
35
catalog-info.yaml
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
apiVersion: backstage.io/v1alpha1
|
||||||
|
kind: Component
|
||||||
|
metadata:
|
||||||
|
name: auto-retrieve-files-from-a-reposito
|
||||||
|
description: "Fetch all Java workflow files from the Gitea repository"
|
||||||
|
annotations:
|
||||||
|
backstage.io/kubernetes-label-selector: app=auto-retrieve-files-from-a-reposito
|
||||||
|
backstage.io/kubernetes-namespace: agents
|
||||||
|
backstage.io/techdocs-ref: dir:.
|
||||||
|
gitea.kyndemo.live/repo-slug: generated-agents/auto-retrieve-files-from-a-reposito
|
||||||
|
grafana/grafana-instance: default
|
||||||
|
grafana/alert-label-selector: app=auto-retrieve-files-from-a-reposito
|
||||||
|
grafana/dashboard-selector: uid == 'otel-app-observability-v2'
|
||||||
|
grafana.com/dashboard-url: https://grafana.kyndemo.live/d/otel-app-observability-v2/opentelemetry-application-observability?orgId=1&var-app=auto-retrieve-files-from-a-reposito
|
||||||
|
tags:
|
||||||
|
- agent
|
||||||
|
- a2a
|
||||||
|
- auto-generated
|
||||||
|
links:
|
||||||
|
- icon: github
|
||||||
|
title: Source Repository
|
||||||
|
url: https://gitea.kyndemo.live/generated-agents/auto-retrieve-files-from-a-reposito
|
||||||
|
- icon: code
|
||||||
|
title: CI/CD Pipelines
|
||||||
|
url: https://gitea.kyndemo.live/generated-agents/auto-retrieve-files-from-a-reposito/actions
|
||||||
|
- icon: dashboard
|
||||||
|
title: Grafana Dashboard
|
||||||
|
url: https://grafana.kyndemo.live/d/otel-app-observability-v2/opentelemetry-application-observability?orgId=1&var-app=auto-retrieve-files-from-a-reposito
|
||||||
|
spec:
|
||||||
|
type: service
|
||||||
|
lifecycle: experimental
|
||||||
|
owner: group:default/agentic-agents
|
||||||
|
system: agentic-agents
|
||||||
|
dependsOn:
|
||||||
|
- resource:default/cjot-aks
|
||||||
13
k8s/configmap.yaml
Normal file
13
k8s/configmap.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: auto-retrieve-files-from-a-reposito-config
|
||||||
|
namespace: agents
|
||||||
|
data:
|
||||||
|
REGISTRY_URL: "http://agent-gateway.agents.svc.cluster.local"
|
||||||
|
AGENT_SELF_URL: "http://auto-retrieve-files-from-a-reposito.agents.svc.cluster.local"
|
||||||
|
AZURE_OPENAI_DEPLOYMENT: "gpt-4o"
|
||||||
|
AZURE_OPENAI_API_VERSION: "2024-08-01-preview"
|
||||||
|
LOG_LEVEL: "INFO"
|
||||||
|
OTEL_SERVICE_NAME: "auto-retrieve-files-from-a-reposito"
|
||||||
|
OTEL_EXPORTER_OTLP_ENDPOINT: "http://otel-collector.monitoring.svc.cluster.local:4318"
|
||||||
81
k8s/deployment.yaml
Normal file
81
k8s/deployment.yaml
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: auto-retrieve-files-from-a-reposito
|
||||||
|
namespace: agents
|
||||||
|
labels:
|
||||||
|
app: auto-retrieve-files-from-a-reposito
|
||||||
|
component: agent
|
||||||
|
generated-by: agent-factory
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: auto-retrieve-files-from-a-reposito
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: auto-retrieve-files-from-a-reposito
|
||||||
|
azure.workload.identity/use: "true"
|
||||||
|
annotations:
|
||||||
|
instrumentation.opentelemetry.io/inject-python: "monitoring/otel-instrumentation"
|
||||||
|
spec:
|
||||||
|
serviceAccountName: agents-sa
|
||||||
|
containers:
|
||||||
|
- name: auto-retrieve-files-from-a-reposito
|
||||||
|
image: bstagecjotdevacr.azurecr.io/auto-retrieve-files-from-a-reposito:latest
|
||||||
|
imagePullPolicy: Always
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 8080
|
||||||
|
protocol: TCP
|
||||||
|
envFrom:
|
||||||
|
- configMapRef:
|
||||||
|
name: auto-retrieve-files-from-a-reposito-config
|
||||||
|
env:
|
||||||
|
- name: AZURE_OPENAI_ENDPOINT
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: agents-kv-sync
|
||||||
|
key: azure-openai-endpoint
|
||||||
|
- name: AZURE_OPENAI_API_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: agents-kv-sync
|
||||||
|
key: azure-openai-api-key
|
||||||
|
- name: OTEL_SERVICE_NAME
|
||||||
|
value: "auto-retrieve-files-from-a-reposito"
|
||||||
|
- name: OTEL_RESOURCE_ATTRIBUTES
|
||||||
|
value: "service.namespace=agents,deployment.environment=production"
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "250m"
|
||||||
|
limits:
|
||||||
|
memory: "1Gi"
|
||||||
|
cpu: "500m"
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 30
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 5
|
||||||
|
volumeMounts:
|
||||||
|
- name: secrets-store
|
||||||
|
mountPath: "/mnt/secrets-store"
|
||||||
|
readOnly: true
|
||||||
|
volumes:
|
||||||
|
- name: secrets-store
|
||||||
|
csi:
|
||||||
|
driver: secrets-store.csi.k8s.io
|
||||||
|
readOnly: true
|
||||||
|
volumeAttributes:
|
||||||
|
secretProviderClass: agents-kv-spc
|
||||||
16
k8s/service.yaml
Normal file
16
k8s/service.yaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: auto-retrieve-files-from-a-reposito
|
||||||
|
namespace: agents
|
||||||
|
labels:
|
||||||
|
app: auto-retrieve-files-from-a-reposito
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: http
|
||||||
|
protocol: TCP
|
||||||
|
name: http
|
||||||
|
selector:
|
||||||
|
app: auto-retrieve-files-from-a-reposito
|
||||||
18
requirements.txt
Normal file
18
requirements.txt
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Auto-generated by Agent Factory
|
||||||
|
uvicorn[standard]==0.32.1
|
||||||
|
starlette>=0.28.0
|
||||||
|
pydantic>=2.11.3
|
||||||
|
python-dotenv==1.0.1
|
||||||
|
httpx>=0.28.1
|
||||||
|
click>=8.1.8
|
||||||
|
|
||||||
|
# A2A Protocol
|
||||||
|
a2a-sdk[http-server]>=0.3.0
|
||||||
|
|
||||||
|
# LangChain & LangGraph
|
||||||
|
langchain>=1.2.10
|
||||||
|
langchain-openai>=0.2.12
|
||||||
|
langchain-core>=1.2.11
|
||||||
|
langgraph>=0.2.59
|
||||||
|
langgraph-checkpoint>=2.0.6
|
||||||
|
openai>=1.109.1
|
||||||
54
scripts/deploy.sh
Normal file
54
scripts/deploy.sh
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# deploy.sh — Build auto-retrieve-files-from-a-reposito image in ACR and deploy to AKS
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||||
|
ACR_NAME="bstagecjotdevacr"
|
||||||
|
APP_NAME="auto-retrieve-files-from-a-reposito"
|
||||||
|
NAMESPACE="agents"
|
||||||
|
VERSION_FILE="${SCRIPT_DIR}/../.image-version"
|
||||||
|
TAG=""
|
||||||
|
|
||||||
|
while [[ "$#" -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
--tag) TAG="$2"; shift ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "$TAG" ]; then
|
||||||
|
if [ -f "$VERSION_FILE" ]; then
|
||||||
|
CURRENT_VERSION=$(cat "$VERSION_FILE")
|
||||||
|
else
|
||||||
|
CURRENT_VERSION="1.0.0"
|
||||||
|
fi
|
||||||
|
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION"
|
||||||
|
PATCH=$((PATCH + 1))
|
||||||
|
TAG="${MAJOR}.${MINOR}.${PATCH}"
|
||||||
|
echo "$TAG" > "$VERSION_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
IMAGE="${ACR_NAME}.azurecr.io/${APP_NAME}:${TAG}"
|
||||||
|
|
||||||
|
echo "======================================================================"
|
||||||
|
echo " auto-retrieve-files-from-a-reposito — Build & Deploy"
|
||||||
|
echo " Image: ${IMAGE}"
|
||||||
|
echo "======================================================================"
|
||||||
|
|
||||||
|
az acr build --registry ${ACR_NAME} \
|
||||||
|
--image ${APP_NAME}:${TAG} \
|
||||||
|
--image ${APP_NAME}:latest \
|
||||||
|
"${SCRIPT_DIR}/.."
|
||||||
|
|
||||||
|
kubectl apply -f "${SCRIPT_DIR}/../k8s/configmap.yaml" 2>/dev/null || true
|
||||||
|
kubectl apply -f "${SCRIPT_DIR}/../k8s/deployment.yaml"
|
||||||
|
kubectl apply -f "${SCRIPT_DIR}/../k8s/service.yaml" 2>/dev/null || true
|
||||||
|
|
||||||
|
kubectl set image deployment/${APP_NAME} \
|
||||||
|
${APP_NAME}=${IMAGE} \
|
||||||
|
-n ${NAMESPACE}
|
||||||
|
|
||||||
|
kubectl rollout status deployment/${APP_NAME} -n ${NAMESPACE} --timeout=120s
|
||||||
|
|
||||||
|
echo "✓ Done. Image: ${IMAGE}"
|
||||||
|
echo " Port forward: kubectl port-forward -n ${NAMESPACE} deployment/${APP_NAME} 8080:8080"
|
||||||
66
scripts/full-deploy.sh
Normal file
66
scripts/full-deploy.sh
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# full-deploy.sh — Preflight + build + deploy auto-retrieve-files-from-a-reposito to AKS
|
||||||
|
set -e
|
||||||
|
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||||
|
ACR_NAME="bstagecjotdevacr"
|
||||||
|
APP_NAME="auto-retrieve-files-from-a-reposito"
|
||||||
|
NAMESPACE="agents"
|
||||||
|
VERSION_FILE="${SCRIPT_DIR}/../.image-version"
|
||||||
|
TAG=""
|
||||||
|
|
||||||
|
while [[ "$#" -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
--tag) TAG="$2"; shift ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
print_success() { echo -e "${GREEN}✓ $1${NC}"; }
|
||||||
|
print_error() { echo -e "${RED}✗ $1${NC}"; exit 1; }
|
||||||
|
|
||||||
|
command -v kubectl &>/dev/null || print_error "kubectl not found."
|
||||||
|
command -v az &>/dev/null || print_error "Azure CLI not found."
|
||||||
|
az account show &>/dev/null || print_error "Not logged in to Azure."
|
||||||
|
kubectl cluster-info &>/dev/null || print_error "Cannot connect to cluster."
|
||||||
|
CLUSTER=$(kubectl config current-context)
|
||||||
|
print_success "Connected to cluster: ${CLUSTER}"
|
||||||
|
|
||||||
|
if [ -z "$TAG" ]; then
|
||||||
|
if [ -f "$VERSION_FILE" ]; then
|
||||||
|
CURRENT_VERSION=$(cat "$VERSION_FILE")
|
||||||
|
else
|
||||||
|
CURRENT_VERSION="1.0.0"
|
||||||
|
fi
|
||||||
|
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION"
|
||||||
|
PATCH=$((PATCH + 1))
|
||||||
|
TAG="${MAJOR}.${MINOR}.${PATCH}"
|
||||||
|
echo "$TAG" > "$VERSION_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
IMAGE="${ACR_NAME}.azurecr.io/${APP_NAME}:${TAG}"
|
||||||
|
print_success "Image tag: ${TAG}"
|
||||||
|
|
||||||
|
az acr build --registry ${ACR_NAME} \
|
||||||
|
--image ${APP_NAME}:${TAG} \
|
||||||
|
--image ${APP_NAME}:latest \
|
||||||
|
"${SCRIPT_DIR}/.." || print_error "ACR build failed."
|
||||||
|
print_success "Image built: ${IMAGE}"
|
||||||
|
|
||||||
|
kubectl apply -f "${SCRIPT_DIR}/../k8s/configmap.yaml" 2>/dev/null || true
|
||||||
|
kubectl apply -f "${SCRIPT_DIR}/../k8s/deployment.yaml" || print_error "Failed to apply deployment."
|
||||||
|
kubectl apply -f "${SCRIPT_DIR}/../k8s/service.yaml" || print_error "Failed to apply service."
|
||||||
|
print_success "Manifests applied"
|
||||||
|
|
||||||
|
kubectl set image deployment/${APP_NAME} ${APP_NAME}=${IMAGE} -n ${NAMESPACE}
|
||||||
|
kubectl rollout status deployment/${APP_NAME} -n ${NAMESPACE} --timeout=180s || \
|
||||||
|
print_error "Rollout failed."
|
||||||
|
print_success "Rollout complete"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN} auto-retrieve-files-from-a-reposito deployed: ${IMAGE}${NC}"
|
||||||
|
echo " Port forward: kubectl port-forward -n ${NAMESPACE} deployment/${APP_NAME} 8080:8080"
|
||||||
Reference in New Issue
Block a user