Compare commits
3 Commits
69441fa180
...
1ae1456502
| Author | SHA1 | Date | |
|---|---|---|---|
| 1ae1456502 | |||
| df43c58028 | |||
| a8e55a4a8d |
@@ -1,9 +1,16 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Deploy UNT (NOVA) to server
|
# Deploy UNT (NOVA) to server
|
||||||
# Usage: ./ctrl/deploy.sh [rsync|edge]
|
# Usage: ./ctrl/deploy.sh [rsync|sync|restart|push|edge]
|
||||||
#
|
#
|
||||||
# rsync — sync source to server and rebuild there (bypass CI)
|
# rsync — sync source, rebuild images on server, restart (bypass CI)
|
||||||
# edge — pull latest images and restart containers
|
# sync — sync source only (no rebuild, no restart)
|
||||||
|
# restart — restart containers (no sync, no rebuild)
|
||||||
|
# push — build images locally, push to registry, deploy (avoids OOM on server)
|
||||||
|
# edge — pull latest images from registry and restart
|
||||||
|
#
|
||||||
|
# Note: code is baked into the image (no volume mounts), so code changes
|
||||||
|
# need a rebuild (rsync | edge). Config-only changes (docker-compose, .env
|
||||||
|
# already on server) can use `restart`.
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
cd "$(dirname "$0")/.."
|
cd "$(dirname "$0")/.."
|
||||||
@@ -11,14 +18,16 @@ cd "$(dirname "$0")/.."
|
|||||||
SERVER="mcrn.ar"
|
SERVER="mcrn.ar"
|
||||||
REMOTE_DIR="~/unt"
|
REMOTE_DIR="~/unt"
|
||||||
|
|
||||||
case "${1:-rsync}" in
|
do_sync() {
|
||||||
rsync)
|
|
||||||
echo "=== Syncing source to $SERVER ==="
|
echo "=== Syncing source to $SERVER ==="
|
||||||
rsync -avz --exclude='.git' --exclude='node_modules' --exclude='.venv' \
|
rsync -avz --exclude='.git' --exclude='node_modules' --exclude='.venv' \
|
||||||
--exclude='ui/app/dist' --exclude='__pycache__' \
|
--exclude='ui/app/dist' --exclude='__pycache__' \
|
||||||
|
--exclude='ctrl/edge/.env' \
|
||||||
--filter=':- .gitignore' \
|
--filter=':- .gitignore' \
|
||||||
. "$SERVER:$REMOTE_DIR/"
|
. "$SERVER:$REMOTE_DIR/"
|
||||||
|
}
|
||||||
|
|
||||||
|
do_rebuild_and_restart() {
|
||||||
echo "=== Building and restarting on server ==="
|
echo "=== Building and restarting on server ==="
|
||||||
ssh "$SERVER" << 'EOF'
|
ssh "$SERVER" << 'EOF'
|
||||||
cd ~/unt
|
cd ~/unt
|
||||||
@@ -26,27 +35,69 @@ case "${1:-rsync}" in
|
|||||||
docker build -t registry.mcrn.ar/unt/ui:latest -f ctrl/Dockerfile.ui .
|
docker build -t registry.mcrn.ar/unt/ui:latest -f ctrl/Dockerfile.ui .
|
||||||
cd ctrl/edge
|
cd ctrl/edge
|
||||||
[ -f .env ] || cp .env.example .env
|
[ -f .env ] || cp .env.example .env
|
||||||
docker compose up -d --remove-orphans
|
docker compose up -d --remove-orphans --force-recreate
|
||||||
|
docker image prune -f
|
||||||
|
docker compose ps
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
do_restart() {
|
||||||
|
echo "=== Restarting containers on $SERVER ==="
|
||||||
|
ssh "$SERVER" << 'EOF'
|
||||||
|
cd ~/unt/ctrl/edge
|
||||||
|
docker compose up -d --remove-orphans --force-recreate
|
||||||
|
docker compose ps
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1:-rsync}" in
|
||||||
|
rsync)
|
||||||
|
do_sync
|
||||||
|
do_rebuild_and_restart
|
||||||
|
;;
|
||||||
|
|
||||||
|
sync)
|
||||||
|
do_sync
|
||||||
|
;;
|
||||||
|
|
||||||
|
restart)
|
||||||
|
do_restart
|
||||||
|
;;
|
||||||
|
|
||||||
|
push)
|
||||||
|
echo "=== Building images locally ==="
|
||||||
|
docker build -t registry.mcrn.ar/unt/api:latest -f ctrl/Dockerfile.api .
|
||||||
|
docker build -t registry.mcrn.ar/unt/ui:latest -f ctrl/Dockerfile.ui .
|
||||||
|
|
||||||
|
echo "=== Pushing to registry ==="
|
||||||
|
/home/mariano/wdir/ppl/ctrl/push-image.sh unt/api latest
|
||||||
|
/home/mariano/wdir/ppl/ctrl/push-image.sh unt/ui latest
|
||||||
|
|
||||||
|
echo "=== Pulling and restarting on $SERVER ==="
|
||||||
|
ssh "$SERVER" << 'EOF'
|
||||||
|
cd ~/unt/ctrl/edge
|
||||||
|
docker compose pull
|
||||||
|
docker compose up -d --remove-orphans --force-recreate
|
||||||
docker image prune -f
|
docker image prune -f
|
||||||
docker compose ps
|
docker compose ps
|
||||||
EOF
|
EOF
|
||||||
;;
|
;;
|
||||||
|
|
||||||
edge)
|
edge)
|
||||||
echo "=== Pulling and restarting on $SERVER ==="
|
echo "=== Pulling latest images on $SERVER ==="
|
||||||
ssh "$SERVER" << 'EOF'
|
ssh "$SERVER" << 'EOF'
|
||||||
cd ~/unt/ctrl/edge
|
cd ~/unt/ctrl/edge
|
||||||
docker compose pull
|
docker compose pull
|
||||||
docker compose up -d --remove-orphans
|
docker compose up -d --remove-orphans --force-recreate
|
||||||
docker image prune -f
|
docker image prune -f
|
||||||
docker compose ps
|
docker compose ps
|
||||||
EOF
|
EOF
|
||||||
;;
|
;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
echo "Usage: $0 [rsync|edge]"
|
echo "Usage: $0 [rsync|sync|restart|push|edge]"
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
echo "=== Deploy complete ==="
|
echo "=== Done ==="
|
||||||
|
|||||||
@@ -5,50 +5,46 @@ digraph deployment {
|
|||||||
node [fontname="Helvetica" fontsize=10 style=filled color="#1e2a4a" fontcolor="#e8eaf0"]
|
node [fontname="Helvetica" fontsize=10 style=filled color="#1e2a4a" fontcolor="#e8eaf0"]
|
||||||
edge [fontname="Helvetica" fontsize=9 fontcolor="#8892a8" color="#4a5568"]
|
edge [fontname="Helvetica" fontsize=9 fontcolor="#8892a8" color="#4a5568"]
|
||||||
|
|
||||||
label="Deployment — Kind Cluster (dev) / EC2 (prod)"
|
label="Deployment — Kind Clusters (dev) / EC2 (prod)"
|
||||||
labelloc=t
|
labelloc=t
|
||||||
fontsize=14
|
fontsize=14
|
||||||
fontcolor="#0066ff"
|
fontcolor="#0066ff"
|
||||||
|
|
||||||
user [label="Browser\nlocalhost:8040" fillcolor="#243056" shape=box]
|
user [label="Browser" fillcolor="#243056" shape=box]
|
||||||
|
|
||||||
subgraph cluster_kind {
|
subgraph cluster_ec2 {
|
||||||
label="Kind Cluster: unt (namespace: unt)"
|
label="EC2 (mcrn.ar)"
|
||||||
|
color="#ff9800"
|
||||||
|
fontcolor="#ff9800"
|
||||||
|
style=rounded
|
||||||
|
|
||||||
|
nginx_edge [label="nginx (gateway container)\n443 · SSL\nstellarair.mcrn.ar\nlangfuse.mcrn.ar\nnova.mcrn.ar (Kong backend)" fillcolor="#121829" shape=box]
|
||||||
|
nova_ui [label="nova-ui\nnginx + Vue build" fillcolor="#0d1a33" shape=box]
|
||||||
|
nova_api [label="nova-api\nuvicorn · FastAPI\nMCP clients (stdio)" fillcolor="#0d1a33" shape=box]
|
||||||
|
}
|
||||||
|
|
||||||
|
subgraph cluster_kind_unt {
|
||||||
|
label="Kind Cluster: unt (local dev)"
|
||||||
color="#0066ff"
|
color="#0066ff"
|
||||||
fontcolor="#0066ff"
|
fontcolor="#0066ff"
|
||||||
style=rounded
|
style=rounded
|
||||||
|
|
||||||
subgraph cluster_frontend_pod {
|
unt_ui [label="ui pod\nnginx + Vue\nNodePort 30040" fillcolor="#121829" shape=box]
|
||||||
label="Pod: ui"
|
unt_api [label="api pod\nuvicorn · FastAPI" fillcolor="#121829" shape=box]
|
||||||
color="#1e2a4a"
|
|
||||||
fontcolor="#4a5568"
|
|
||||||
ui [label="nginx\n:80\n\nVue SPA\nProxy → api:8000" fillcolor="#121829" shape=box]
|
|
||||||
ui_svc [label="Service: ui\nNodePort 30040" fillcolor="#0d1a33" shape=diamond fontsize=9]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
subgraph cluster_api_pod {
|
subgraph cluster_kind_lng {
|
||||||
label="Pod: api"
|
label="Kind Cluster: lng (shared observability)"
|
||||||
color="#1e2a4a"
|
color="#00c853"
|
||||||
fontcolor="#4a5568"
|
fontcolor="#00c853"
|
||||||
api [label="uvicorn\n:8000\n\nFastAPI\nMCP clients (stdio)\nLangGraph agents" fillcolor="#121829" shape=box]
|
style=rounded
|
||||||
api_svc [label="Service: api\nClusterIP" fillcolor="#0d1a33" shape=diamond fontsize=9]
|
|
||||||
}
|
|
||||||
|
|
||||||
subgraph cluster_langfuse_pod {
|
lf_web [label="langfuse-web\nNext.js\nNodePort 30030" fillcolor="#121829" shape=box]
|
||||||
label="Pod: langfuse"
|
lf_worker [label="langfuse-worker\nClickHouse writer" fillcolor="#121829" shape=box]
|
||||||
color="#1e2a4a"
|
lf_ch [label="ClickHouse\ntraces · spans" fillcolor="#0d1a33" shape=cylinder]
|
||||||
fontcolor="#4a5568"
|
lf_pg [label="Postgres\nmetadata" fillcolor="#0d1a33" shape=cylinder]
|
||||||
langfuse [label="Langfuse\n:3000\n\nTrace viewer" fillcolor="#121829" shape=box]
|
lf_redis [label="Redis\nqueue · cache" fillcolor="#0d1a33" shape=cylinder]
|
||||||
langfuse_svc [label="Service: langfuse\nNodePort 30030" fillcolor="#0d1a33" shape=diamond fontsize=9]
|
lf_minio [label="MinIO\nS3 events" fillcolor="#0d1a33" shape=cylinder]
|
||||||
}
|
|
||||||
|
|
||||||
subgraph cluster_pg_pod {
|
|
||||||
label="Pod: postgres"
|
|
||||||
color="#1e2a4a"
|
|
||||||
fontcolor="#4a5568"
|
|
||||||
pg [label="PostgreSQL\n:5432\n\nLangfuse data" fillcolor="#121829" shape=cylinder]
|
|
||||||
pg_svc [label="Service: postgres\nClusterIP" fillcolor="#0d1a33" shape=diamond fontsize=9]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
subgraph cluster_external {
|
subgraph cluster_external {
|
||||||
@@ -58,25 +54,33 @@ digraph deployment {
|
|||||||
style=dashed
|
style=dashed
|
||||||
ext_weather [label="OpenMeteo" fillcolor="#0d2a0d" shape=octagon fontcolor="#00c853"]
|
ext_weather [label="OpenMeteo" fillcolor="#0d2a0d" shape=octagon fontcolor="#00c853"]
|
||||||
ext_faa [label="FAA" fillcolor="#0d2a0d" shape=octagon fontcolor="#00c853"]
|
ext_faa [label="FAA" fillcolor="#0d2a0d" shape=octagon fontcolor="#00c853"]
|
||||||
ext_bedrock [label="AWS Bedrock" fillcolor="#243056" shape=octagon]
|
ext_bedrock [label="Bedrock / Groq\nAnthropic / OpenAI" fillcolor="#243056" shape=octagon]
|
||||||
ext_kong [label="Kong Konnect\n(optional)" fillcolor="#243056" shape=octagon style="filled,dashed"]
|
ext_kong [label="Kong Konnect\n(optional gateway)" fillcolor="#243056" shape=octagon style="filled,dashed"]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Port mappings
|
// Prod path
|
||||||
user -> ui_svc [label="host:8040 → 30040" color="#0066ff"]
|
user -> nginx_edge [label="stellarair.mcrn.ar" color="#ff9800"]
|
||||||
ui_svc -> ui
|
user -> ext_kong [label="(API governance)" style=dashed color="#4a5568"]
|
||||||
ui -> api_svc [label="proxy"]
|
ext_kong -> nginx_edge [label="X-Gateway-Secret" style=dashed color="#4a5568"]
|
||||||
api_svc -> api
|
nginx_edge -> nova_ui
|
||||||
|
nova_ui -> nova_api [label="/agents /scenarios"]
|
||||||
|
nova_api -> ext_weather [label="HTTP" color="#00c853"]
|
||||||
|
nova_api -> ext_faa [label="HTTP" color="#00c853"]
|
||||||
|
nova_api -> ext_bedrock [label="LLM calls" style=dashed]
|
||||||
|
|
||||||
api -> ext_weather [label="HTTP" color="#00c853"]
|
// Dev path
|
||||||
api -> ext_faa [label="HTTP" color="#00c853"]
|
user -> unt_ui [label="localhost:8040" color="#0066ff"]
|
||||||
api -> ext_bedrock [label="Converse API" style=dashed]
|
unt_ui -> unt_api
|
||||||
api -> langfuse_svc [label="traces" style=dotted]
|
unt_api -> ext_weather [style=dashed color="#00c853"]
|
||||||
|
unt_api -> ext_faa [style=dashed color="#00c853"]
|
||||||
|
unt_api -> ext_bedrock [style=dashed]
|
||||||
|
|
||||||
langfuse_svc -> langfuse
|
// Observability (shared by both dev and prod API)
|
||||||
langfuse -> pg_svc
|
unt_api -> lf_web [label="OTLP traces" style=dotted color="#00c853"]
|
||||||
pg_svc -> pg
|
nova_api -> lf_web [label="OTLP traces" style=dotted color="#00c853"]
|
||||||
|
lf_web -> lf_redis
|
||||||
user -> ext_kong [style=dashed label="(optional)" color="#4a5568"]
|
lf_worker -> lf_redis
|
||||||
ext_kong -> ui_svc [style=dashed color="#4a5568"]
|
lf_worker -> lf_ch
|
||||||
|
lf_web -> lf_pg
|
||||||
|
lf_web -> lf_minio
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,222 +4,280 @@
|
|||||||
<!-- Generated by graphviz version 14.1.2 (0)
|
<!-- Generated by graphviz version 14.1.2 (0)
|
||||||
-->
|
-->
|
||||||
<!-- Title: deployment Pages: 1 -->
|
<!-- Title: deployment Pages: 1 -->
|
||||||
<svg style="background:#0a0e17" width="1496pt" height="2167pt"
|
<svg width="947pt" height="632pt"
|
||||||
viewBox="0.00 0.00 1496.00 2167.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
viewBox="0.00 0.00 947.00 632.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
<g id="graph0" class="graph" transform="scale(2 2) rotate(0) translate(4 1079.34)">
|
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 628.34)">
|
||||||
<title>deployment</title>
|
<title>deployment</title>
|
||||||
<polygon fill="#0a0e17" stroke="none" points="-4,4 -4,-1079.34 744,-1079.34 744,4 -4,4"/>
|
<polygon fill="#0a0e17" stroke="none" points="-4,4 -4,-628.34 943,-628.34 943,4 -4,4"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="370" y="-1058.04" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#0066ff">Deployment — Kind Cluster (dev) / EC2 (prod)</text>
|
<text xml:space="preserve" text-anchor="middle" x="469.5" y="-607.04" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#0066ff">Deployment — Kind Clusters (dev) / EC2 (prod)</text>
|
||||||
<g id="clust1" class="cluster">
|
<g id="clust1" class="cluster">
|
||||||
<title>cluster_kind</title>
|
<title>cluster_ec2</title>
|
||||||
<path fill="#0a0e17" stroke="#0066ff" d="M20,-8C20,-8 260,-8 260,-8 266,-8 272,-14 272,-20 272,-20 272,-964.84 272,-964.84 272,-970.84 266,-976.84 260,-976.84 260,-976.84 20,-976.84 20,-976.84 14,-976.84 8,-970.84 8,-964.84 8,-964.84 8,-20 8,-20 8,-14 14,-8 20,-8"/>
|
<path fill="#0a0e17" stroke="#ff9800" d="M536,-212.84C536,-212.84 686,-212.84 686,-212.84 692,-212.84 698,-218.84 698,-224.84 698,-224.84 698,-513.84 698,-513.84 698,-519.84 692,-525.84 686,-525.84 686,-525.84 536,-525.84 536,-525.84 530,-525.84 524,-519.84 524,-513.84 524,-513.84 524,-224.84 524,-224.84 524,-218.84 530,-212.84 536,-212.84"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="140" y="-959.54" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#0066ff">Kind Cluster: unt  (namespace: unt)</text>
|
<text xml:space="preserve" text-anchor="middle" x="611" y="-508.54" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#ff9800">EC2 (mcrn.ar)</text>
|
||||||
</g>
|
</g>
|
||||||
<g id="clust2" class="cluster">
|
<g id="clust2" class="cluster">
|
||||||
<title>cluster_frontend_pod</title>
|
<title>cluster_kind_unt</title>
|
||||||
<path fill="#0a0e17" stroke="#1e2a4a" d="M80,-733.34C80,-733.34 252,-733.34 252,-733.34 258,-733.34 264,-739.34 264,-745.34 264,-745.34 264,-931.59 264,-931.59 264,-937.59 258,-943.59 252,-943.59 252,-943.59 80,-943.59 80,-943.59 74,-943.59 68,-937.59 68,-931.59 68,-931.59 68,-745.34 68,-745.34 68,-739.34 74,-733.34 80,-733.34"/>
|
<path fill="#0a0e17" stroke="#0066ff" d="M280,-217.97C280,-217.97 465,-217.97 465,-217.97 471,-217.97 477,-223.97 477,-229.97 477,-229.97 477,-381.84 477,-381.84 477,-387.84 471,-393.84 465,-393.84 465,-393.84 280,-393.84 280,-393.84 274,-393.84 268,-387.84 268,-381.84 268,-381.84 268,-229.97 268,-229.97 268,-223.97 274,-217.97 280,-217.97"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="166" y="-926.29" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#4a5568">Pod: ui</text>
|
<text xml:space="preserve" text-anchor="middle" x="372.5" y="-376.54" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#0066ff">Kind Cluster: unt (local dev)</text>
|
||||||
</g>
|
</g>
|
||||||
<g id="clust3" class="cluster">
|
<g id="clust3" class="cluster">
|
||||||
<title>cluster_api_pod</title>
|
<title>cluster_kind_lng</title>
|
||||||
<path fill="#0a0e17" stroke="#1e2a4a" d="M122,-481.09C122,-481.09 252,-481.09 252,-481.09 258,-481.09 264,-487.09 264,-493.09 264,-493.09 264,-692.09 264,-692.09 264,-698.09 258,-704.09 252,-704.09 252,-704.09 122,-704.09 122,-704.09 116,-704.09 110,-698.09 110,-692.09 110,-692.09 110,-493.09 110,-493.09 110,-487.09 116,-481.09 122,-481.09"/>
|
<path fill="#0a0e17" stroke="#00c853" d="M20,-8C20,-8 361,-8 361,-8 367,-8 373,-14 373,-20 373,-20 373,-169.08 373,-169.08 373,-175.08 367,-181.08 361,-181.08 361,-181.08 20,-181.08 20,-181.08 14,-181.08 8,-175.08 8,-169.08 8,-169.08 8,-20 8,-20 8,-14 14,-8 20,-8"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="187" y="-686.79" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#4a5568">Pod: api</text>
|
<text xml:space="preserve" text-anchor="middle" x="190.5" y="-163.78" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#00c853">Kind Cluster: lng (shared observability)</text>
|
||||||
</g>
|
</g>
|
||||||
<g id="clust4" class="cluster">
|
<g id="clust4" class="cluster">
|
||||||
<title>cluster_langfuse_pod</title>
|
|
||||||
<path fill="#0a0e17" stroke="#1e2a4a" d="M74,-254.34C74,-254.34 252,-254.34 252,-254.34 258,-254.34 264,-260.34 264,-266.34 264,-266.34 264,-439.84 264,-439.84 264,-445.84 258,-451.84 252,-451.84 252,-451.84 74,-451.84 74,-451.84 68,-451.84 62,-445.84 62,-439.84 62,-439.84 62,-266.34 62,-266.34 62,-260.34 68,-254.34 74,-254.34"/>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="163" y="-434.54" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#4a5568">Pod: langfuse</text>
|
|
||||||
</g>
|
|
||||||
<g id="clust5" class="cluster">
|
|
||||||
<title>cluster_pg_pod</title>
|
|
||||||
<path fill="#0a0e17" stroke="#1e2a4a" d="M72,-16C72,-16 252,-16 252,-16 258,-16 264,-22 264,-28 264,-28 264,-223.34 264,-223.34 264,-229.34 258,-235.34 252,-235.34 252,-235.34 72,-235.34 72,-235.34 66,-235.34 60,-229.34 60,-223.34 60,-223.34 60,-28 60,-28 60,-22 66,-16 72,-16"/>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="162" y="-218.04" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#4a5568">Pod: postgres</text>
|
|
||||||
</g>
|
|
||||||
<g id="clust6" class="cluster">
|
|
||||||
<title>cluster_external</title>
|
<title>cluster_external</title>
|
||||||
<polygon fill="#0a0e17" stroke="#00c853" stroke-dasharray="5,2" points="280,-354.45 280,-446.98 732,-446.98 732,-354.45 280,-354.45"/>
|
<polygon fill="#0a0e17" stroke="#00c853" stroke-dasharray="5,2" points="381,-91.06 381,-183.59 931,-183.59 931,-91.06 381,-91.06"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="506" y="-429.68" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#00c853">External APIs</text>
|
<text xml:space="preserve" text-anchor="middle" x="656" y="-166.29" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#00c853">External APIs</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- user -->
|
<!-- user -->
|
||||||
<g id="node1" class="node">
|
<g id="node1" class="node">
|
||||||
<title>user</title>
|
<title>user</title>
|
||||||
<polygon fill="#243056" stroke="#1e2a4a" points="465.62,-1050.09 378.38,-1050.09 378.38,-1014.09 465.62,-1014.09 465.62,-1050.09"/>
|
<polygon fill="#243056" stroke="#1e2a4a" points="638.88,-599.09 583.12,-599.09 583.12,-563.09 638.88,-563.09 638.88,-599.09"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="422" y="-1035.34" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Browser</text>
|
<text xml:space="preserve" text-anchor="middle" x="611" y="-577.97" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Browser</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="422" y="-1022.59" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">localhost:8040</text>
|
|
||||||
</g>
|
</g>
|
||||||
<!-- ui_svc -->
|
<!-- nginx_edge -->
|
||||||
<g id="node3" class="node">
|
<g id="node2" class="node">
|
||||||
<title>ui_svc</title>
|
<title>nginx_edge</title>
|
||||||
<polygon fill="#0d1a33" stroke="#1e2a4a" points="166,-910.34 75.75,-879.84 166,-849.34 256.25,-879.84 166,-910.34"/>
|
<polygon fill="#121829" stroke="#1e2a4a" points="690.25,-492.59 531.75,-492.59 531.75,-420.84 690.25,-420.84 690.25,-492.59"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="166" y="-882.54" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#e8eaf0">Service: ui</text>
|
<text xml:space="preserve" text-anchor="middle" x="611" y="-479.09" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">nginx (gateway container)</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="166" y="-871.29" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#e8eaf0">NodePort 30040</text>
|
<text xml:space="preserve" text-anchor="middle" x="611" y="-466.34" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">443 · SSL</text>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="611" y="-453.59" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">stellarair.mcrn.ar</text>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="611" y="-440.84" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">langfuse.mcrn.ar</text>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="611" y="-428.09" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">nova.mcrn.ar (Kong backend)</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- user->ui_svc -->
|
<!-- user->nginx_edge -->
|
||||||
<g id="edge1" class="edge">
|
<g id="edge1" class="edge">
|
||||||
<title>user->ui_svc</title>
|
<title>user->nginx_edge</title>
|
||||||
<path fill="none" stroke="#0066ff" d="M392.38,-1013.71C346.98,-987.06 259.97,-936 208.05,-905.52"/>
|
<path fill="none" stroke="#ff9800" d="M611,-562.82C611,-547.66 611,-524.89 611,-504.42"/>
|
||||||
<polygon fill="#0066ff" stroke="#0066ff" points="209.86,-902.53 199.46,-900.48 206.31,-908.56 209.86,-902.53"/>
|
<polygon fill="#ff9800" stroke="#ff9800" points="614.5,-504.55 611,-494.55 607.5,-504.55 614.5,-504.55"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="405.13" y="-987.54" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8892a8">host:8040 → 30040</text>
|
<text xml:space="preserve" text-anchor="middle" x="649.25" y="-536.54" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8892a8">stellarair.mcrn.ar</text>
|
||||||
|
</g>
|
||||||
|
<!-- unt_ui -->
|
||||||
|
<g id="node5" class="node">
|
||||||
|
<title>unt_ui</title>
|
||||||
|
<polygon fill="#121829" stroke="#1e2a4a" points="469,-360.59 375,-360.59 375,-314.34 469,-314.34 469,-360.59"/>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="422" y="-347.09" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">ui pod</text>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="422" y="-334.34" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">nginx + Vue</text>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="422" y="-321.59" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">NodePort 30040</text>
|
||||||
|
</g>
|
||||||
|
<!-- user->unt_ui -->
|
||||||
|
<g id="edge9" class="edge">
|
||||||
|
<title>user->unt_ui</title>
|
||||||
|
<path fill="none" stroke="#0066ff" d="M582.83,-578.8C546.98,-575.55 485.81,-564.31 453.25,-525.84 416.79,-482.77 415.11,-413.57 418,-372.41"/>
|
||||||
|
<polygon fill="#0066ff" stroke="#0066ff" points="421.48,-372.86 418.84,-362.6 414.5,-372.26 421.48,-372.86"/>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="486.62" y="-453.79" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8892a8">localhost:8040</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- ext_kong -->
|
<!-- ext_kong -->
|
||||||
<g id="node13" class="node">
|
<g id="node16" class="node">
|
||||||
<title>ext_kong</title>
|
<title>ext_kong</title>
|
||||||
<polygon fill="#243056" stroke="#1e2a4a" stroke-dasharray="5,2" points="723.76,-377.47 723.76,-398.71 687,-413.73 635,-413.73 598.24,-398.71 598.24,-377.47 635,-362.45 687,-362.45 723.76,-377.47"/>
|
<polygon fill="#243056" stroke="#1e2a4a" stroke-dasharray="5,2" points="922.85,-114.08 922.85,-135.32 874.32,-150.34 805.68,-150.34 757.15,-135.32 757.15,-114.08 805.68,-99.06 874.32,-99.06 922.85,-114.08"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="661" y="-391.34" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Kong Konnect</text>
|
<text xml:space="preserve" text-anchor="middle" x="840" y="-127.95" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Kong Konnect</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="661" y="-378.59" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">(optional)</text>
|
<text xml:space="preserve" text-anchor="middle" x="840" y="-115.2" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">(optional gateway)</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- user->ext_kong -->
|
<!-- user->ext_kong -->
|
||||||
<g id="edge12" class="edge">
|
|
||||||
<title>user->ext_kong</title>
|
|
||||||
<path fill="none" stroke="#4a5568" stroke-dasharray="5,2" d="M465.88,-1022.95C532.38,-1007.78 651,-968.46 651,-880.84 651,-880.84 651,-880.84 651,-529.97 651,-494.35 654.22,-453.8 657,-425.38"/>
|
|
||||||
<polygon fill="#4a5568" stroke="#4a5568" points="660.48,-425.8 658.01,-415.5 653.52,-425.1 660.48,-425.8"/>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="672.75" y="-714.79" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8892a8">(optional)</text>
|
|
||||||
</g>
|
|
||||||
<!-- ui -->
|
|
||||||
<g id="node2" class="node">
|
|
||||||
<title>ui</title>
|
|
||||||
<polygon fill="#121829" stroke="#1e2a4a" points="229,-812.34 129,-812.34 129,-741.34 229,-741.34 229,-812.34"/>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="179" y="-798.84" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">nginx</text>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="179" y="-786.09" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">:80</text>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="179" y="-761.34" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Vue SPA</text>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="179" y="-748.59" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Proxy → api:8000</text>
|
|
||||||
</g>
|
|
||||||
<!-- api_svc -->
|
|
||||||
<g id="node5" class="node">
|
|
||||||
<title>api_svc</title>
|
|
||||||
<polygon fill="#0d1a33" stroke="#1e2a4a" points="187,-670.84 118.5,-640.34 187,-609.84 255.5,-640.34 187,-670.84"/>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="187" y="-643.04" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#e8eaf0">Service: api</text>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="187" y="-631.79" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#e8eaf0">ClusterIP</text>
|
|
||||||
</g>
|
|
||||||
<!-- ui->api_svc -->
|
|
||||||
<g id="edge3" class="edge">
|
|
||||||
<title>ui->api_svc</title>
|
|
||||||
<path fill="none" stroke="#4a5568" d="M181.08,-740.86C182.16,-722.68 183.49,-700.38 184.61,-681.5"/>
|
|
||||||
<polygon fill="#4a5568" stroke="#4a5568" points="188.09,-681.96 185.19,-671.77 181.1,-681.54 188.09,-681.96"/>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="195.51" y="-714.79" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8892a8">proxy</text>
|
|
||||||
</g>
|
|
||||||
<!-- ui_svc->ui -->
|
|
||||||
<g id="edge2" class="edge">
|
<g id="edge2" class="edge">
|
||||||
<title>ui_svc->ui</title>
|
<title>user->ext_kong</title>
|
||||||
<path fill="none" stroke="#4a5568" d="M169.69,-850.17C170.75,-841.97 171.92,-832.82 173.08,-823.86"/>
|
<path fill="none" stroke="#4a5568" stroke-dasharray="5,2" d="M639.37,-576.2C694.78,-566.84 812,-537.59 812,-457.72 812,-457.72 812,-457.72 812,-242.97 812,-214.91 819.68,-184.08 826.99,-161.07"/>
|
||||||
<polygon fill="#4a5568" stroke="#4a5568" points="176.52,-824.56 174.32,-814.19 169.57,-823.66 176.52,-824.56"/>
|
<polygon fill="#4a5568" stroke="#4a5568" points="830.21,-162.49 830.04,-151.89 823.57,-160.28 830.21,-162.49"/>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="851" y="-334.54" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8892a8">(API governance)</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- api -->
|
<!-- nova_ui -->
|
||||||
|
<g id="node3" class="node">
|
||||||
|
<title>nova_ui</title>
|
||||||
|
<polygon fill="#0d1a33" stroke="#1e2a4a" points="660.12,-355.47 557.88,-355.47 557.88,-319.47 660.12,-319.47 660.12,-355.47"/>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="609" y="-340.72" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">nova-ui</text>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="609" y="-327.97" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">nginx + Vue build</text>
|
||||||
|
</g>
|
||||||
|
<!-- nginx_edge->nova_ui -->
|
||||||
|
<g id="edge4" class="edge">
|
||||||
|
<title>nginx_edge->nova_ui</title>
|
||||||
|
<path fill="none" stroke="#4a5568" d="M610.4,-420.54C610.11,-403.44 609.76,-383.17 609.49,-367.05"/>
|
||||||
|
<polygon fill="#4a5568" stroke="#4a5568" points="612.99,-367.1 609.32,-357.16 605.99,-367.22 612.99,-367.1"/>
|
||||||
|
</g>
|
||||||
|
<!-- nova_api -->
|
||||||
<g id="node4" class="node">
|
<g id="node4" class="node">
|
||||||
<title>api</title>
|
<title>nova_api</title>
|
||||||
<polygon fill="#121829" stroke="#1e2a4a" points="255.75,-572.84 148.25,-572.84 148.25,-489.09 255.75,-489.09 255.75,-572.84"/>
|
<polygon fill="#0d1a33" stroke="#1e2a4a" points="662.75,-267.09 555.25,-267.09 555.25,-220.84 662.75,-220.84 662.75,-267.09"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="202" y="-559.34" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">uvicorn</text>
|
<text xml:space="preserve" text-anchor="middle" x="609" y="-253.59" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">nova-api</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="202" y="-546.59" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">:8000</text>
|
<text xml:space="preserve" text-anchor="middle" x="609" y="-240.84" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">uvicorn · FastAPI</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="202" y="-521.84" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">FastAPI</text>
|
<text xml:space="preserve" text-anchor="middle" x="609" y="-228.09" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">MCP clients (stdio)</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="202" y="-509.09" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">MCP clients (stdio)</text>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="202" y="-496.34" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">LangGraph agents</text>
|
|
||||||
</g>
|
</g>
|
||||||
<!-- langfuse_svc -->
|
<!-- nova_ui->nova_api -->
|
||||||
|
<g id="edge5" class="edge">
|
||||||
|
<title>nova_ui->nova_api</title>
|
||||||
|
<path fill="none" stroke="#4a5568" d="M609,-319.26C609,-307.77 609,-292.29 609,-278.43"/>
|
||||||
|
<polygon fill="#4a5568" stroke="#4a5568" points="612.5,-278.81 609,-268.81 605.5,-278.81 612.5,-278.81"/>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="649.88" y="-287.79" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8892a8">/agents /scenarios</text>
|
||||||
|
</g>
|
||||||
|
<!-- lf_web -->
|
||||||
<g id="node7" class="node">
|
<g id="node7" class="node">
|
||||||
<title>langfuse_svc</title>
|
<title>lf_web</title>
|
||||||
<polygon fill="#0d1a33" stroke="#1e2a4a" points="163,-418.59 69.75,-388.09 163,-357.59 256.25,-388.09 163,-418.59"/>
|
<polygon fill="#121829" stroke="#1e2a4a" points="245,-147.83 151,-147.83 151,-101.58 245,-101.58 245,-147.83"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="163" y="-390.79" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#e8eaf0">Service: langfuse</text>
|
<text xml:space="preserve" text-anchor="middle" x="198" y="-134.33" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">langfuse-web</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="163" y="-379.54" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#e8eaf0">NodePort 30030</text>
|
<text xml:space="preserve" text-anchor="middle" x="198" y="-121.58" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Next.js</text>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="198" y="-108.83" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">NodePort 30030</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- api->langfuse_svc -->
|
<!-- nova_api->lf_web -->
|
||||||
<g id="edge8" class="edge">
|
<g id="edge15" class="edge">
|
||||||
<title>api->langfuse_svc</title>
|
<title>nova_api->lf_web</title>
|
||||||
<path fill="none" stroke="#4a5568" stroke-dasharray="1,5" d="M190.61,-488.84C185.23,-469.38 178.83,-446.29 173.56,-427.22"/>
|
<path fill="none" stroke="#00c853" stroke-dasharray="1,5" d="M555.01,-229.3C532.25,-223.79 505.42,-217.62 481,-212.84 420.96,-201.1 405.73,-199 345,-191.59 324.85,-189.13 272.32,-192.33 254,-183.59 241.18,-177.48 229.72,-167.11 220.55,-156.81"/>
|
||||||
<polygon fill="#4a5568" stroke="#4a5568" points="176.96,-426.4 170.92,-417.69 170.21,-428.27 176.96,-426.4"/>
|
<polygon fill="#00c853" stroke="#00c853" points="223.49,-154.87 214.39,-149.44 218.12,-159.36 223.49,-154.87"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="198.71" y="-462.54" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8892a8">traces</text>
|
<text xml:space="preserve" text-anchor="middle" x="453.63" y="-194.29" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8892a8">OTLP traces</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- ext_weather -->
|
<!-- ext_weather -->
|
||||||
<g id="node10" class="node">
|
<g id="node13" class="node">
|
||||||
<title>ext_weather</title>
|
<title>ext_weather</title>
|
||||||
<polygon fill="#0d2a0d" stroke="#1e2a4a" points="383.85,-380.64 383.85,-395.55 355.82,-406.09 316.18,-406.09 288.15,-395.55 288.15,-380.64 316.18,-370.09 355.82,-370.09 383.85,-380.64"/>
|
<polygon fill="#0d2a0d" stroke="#1e2a4a" points="738.85,-117.25 738.85,-132.16 710.82,-142.7 671.18,-142.7 643.15,-132.16 643.15,-117.25 671.18,-106.7 710.82,-106.7 738.85,-117.25"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="336" y="-384.97" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#00c853">OpenMeteo</text>
|
<text xml:space="preserve" text-anchor="middle" x="691" y="-121.58" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#00c853">OpenMeteo</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- api->ext_weather -->
|
<!-- nova_api->ext_weather -->
|
||||||
<g id="edge5" class="edge">
|
<g id="edge6" class="edge">
|
||||||
<title>api->ext_weather</title>
|
<title>nova_api->ext_weather</title>
|
||||||
<path fill="none" stroke="#00c853" d="M241.12,-488.84C263.97,-464.82 292.08,-435.27 311.75,-414.59"/>
|
<path fill="none" stroke="#00c853" d="M662.06,-220.51C668.98,-215.59 675.29,-209.74 680,-202.84 689.6,-188.78 692.42,-169.89 692.81,-154.32"/>
|
||||||
<polygon fill="#00c853" stroke="#00c853" points="314.22,-417.07 318.58,-407.41 309.15,-412.24 314.22,-417.07"/>
|
<polygon fill="#00c853" stroke="#00c853" points="696.31,-154.68 692.71,-144.71 689.31,-154.75 696.31,-154.68"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="276.23" y="-462.54" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8892a8">HTTP</text>
|
<text xml:space="preserve" text-anchor="middle" x="697.13" y="-194.29" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8892a8">HTTP</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- ext_faa -->
|
<!-- ext_faa -->
|
||||||
<g id="node11" class="node">
|
<g id="node14" class="node">
|
||||||
<title>ext_faa</title>
|
<title>ext_faa</title>
|
||||||
<polygon fill="#0d2a0d" stroke="#1e2a4a" points="456,-380.64 456,-395.55 440.18,-406.09 417.82,-406.09 402,-395.55 402,-380.64 417.82,-370.09 440.18,-370.09 456,-380.64"/>
|
<polygon fill="#0d2a0d" stroke="#1e2a4a" points="625,-117.25 625,-132.16 609.18,-142.7 586.82,-142.7 571,-132.16 571,-117.25 586.82,-106.7 609.18,-106.7 625,-117.25"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="429" y="-384.97" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#00c853">FAA</text>
|
<text xml:space="preserve" text-anchor="middle" x="598" y="-121.58" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#00c853">FAA</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- api->ext_faa -->
|
<!-- nova_api->ext_faa -->
|
||||||
<g id="edge6" class="edge">
|
<g id="edge7" class="edge">
|
||||||
<title>api->ext_faa</title>
|
<title>nova_api->ext_faa</title>
|
||||||
<path fill="none" stroke="#00c853" d="M256.12,-518.06C297.44,-506.72 353.78,-486.18 393,-451.84 403.89,-442.31 412.27,-428.64 418.19,-416.5"/>
|
<path fill="none" stroke="#00c853" d="M642.89,-220.59C651.8,-211.88 657.36,-201.61 651,-191.59 646.53,-184.54 640.24,-189.14 634,-183.59 624.52,-175.15 616.66,-163.63 610.73,-153.08"/>
|
||||||
<polygon fill="#00c853" stroke="#00c853" points="421.23,-418.29 422.15,-407.74 414.84,-415.41 421.23,-418.29"/>
|
<polygon fill="#00c853" stroke="#00c853" points="613.9,-151.58 606.16,-144.35 607.7,-154.83 613.9,-151.58"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="391.29" y="-462.54" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8892a8">HTTP</text>
|
<text xml:space="preserve" text-anchor="middle" x="664.99" y="-194.29" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8892a8">HTTP</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- ext_bedrock -->
|
<!-- ext_bedrock -->
|
||||||
<g id="node12" class="node">
|
<g id="node15" class="node">
|
||||||
<title>ext_bedrock</title>
|
<title>ext_bedrock</title>
|
||||||
<polygon fill="#243056" stroke="#1e2a4a" points="580.31,-380.64 580.31,-395.55 549.08,-406.09 504.92,-406.09 473.69,-395.55 473.69,-380.64 504.92,-370.09 549.08,-370.09 580.31,-380.64"/>
|
<polygon fill="#243056" stroke="#1e2a4a" points="552.7,-114.08 552.7,-135.32 504.84,-150.34 437.16,-150.34 389.3,-135.32 389.3,-114.08 437.16,-99.06 504.84,-99.06 552.7,-114.08"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="527" y="-384.97" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">AWS Bedrock</text>
|
<text xml:space="preserve" text-anchor="middle" x="471" y="-127.95" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Bedrock / Groq</text>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="471" y="-115.2" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Anthropic / OpenAI</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- api->ext_bedrock -->
|
<!-- nova_api->ext_bedrock -->
|
||||||
<g id="edge7" class="edge">
|
<g id="edge8" class="edge">
|
||||||
<title>api->ext_bedrock</title>
|
<title>nova_api->ext_bedrock</title>
|
||||||
<path fill="none" stroke="#4a5568" stroke-dasharray="5,2" d="M256.09,-522.53C311.82,-512.97 399.56,-492.5 465,-451.84 480.6,-442.15 495.18,-427.78 506.29,-415.23"/>
|
<path fill="none" stroke="#4a5568" stroke-dasharray="5,2" d="M603.93,-220.47C600.62,-210.42 595.33,-199.16 587,-191.59 578.37,-183.74 572.56,-188.54 562,-183.59 545.87,-176.03 529.15,-166.09 514.52,-156.59"/>
|
||||||
<polygon fill="#4a5568" stroke="#4a5568" points="508.91,-417.54 512.74,-407.66 503.59,-413 508.91,-417.54"/>
|
<polygon fill="#4a5568" stroke="#4a5568" points="516.76,-153.88 506.49,-151.27 512.9,-159.71 516.76,-153.88"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="475.05" y="-462.54" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8892a8">Converse API</text>
|
<text xml:space="preserve" text-anchor="middle" x="615.8" y="-194.29" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8892a8">LLM calls</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- api_svc->api -->
|
<!-- unt_api -->
|
||||||
<g id="edge4" class="edge">
|
|
||||||
<title>api_svc->api</title>
|
|
||||||
<path fill="none" stroke="#4a5568" d="M190.94,-611.13C192.09,-602.92 193.38,-593.66 194.67,-584.46"/>
|
|
||||||
<polygon fill="#4a5568" stroke="#4a5568" points="198.1,-585.21 196.01,-574.82 191.16,-584.24 198.1,-585.21"/>
|
|
||||||
</g>
|
|
||||||
<!-- langfuse -->
|
|
||||||
<g id="node6" class="node">
|
<g id="node6" class="node">
|
||||||
<title>langfuse</title>
|
<title>unt_api</title>
|
||||||
<polygon fill="#121829" stroke="#1e2a4a" points="200.75,-320.59 123.25,-320.59 123.25,-262.34 200.75,-262.34 200.75,-320.59"/>
|
<polygon fill="#121829" stroke="#1e2a4a" points="469.12,-261.97 372.88,-261.97 372.88,-225.97 469.12,-225.97 469.12,-261.97"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="162" y="-307.09" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Langfuse</text>
|
<text xml:space="preserve" text-anchor="middle" x="421" y="-247.22" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">api pod</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="162" y="-294.34" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">:3000</text>
|
<text xml:space="preserve" text-anchor="middle" x="421" y="-234.47" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">uvicorn · FastAPI</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="162" y="-269.59" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Trace viewer</text>
|
|
||||||
</g>
|
</g>
|
||||||
<!-- pg_svc -->
|
<!-- unt_ui->unt_api -->
|
||||||
<g id="node9" class="node">
|
|
||||||
<title>pg_svc</title>
|
|
||||||
<polygon fill="#0d1a33" stroke="#1e2a4a" points="162,-202.09 68,-171.59 162,-141.09 256,-171.59 162,-202.09"/>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="162" y="-174.29" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#e8eaf0">Service: postgres</text>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="162" y="-163.04" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#e8eaf0">ClusterIP</text>
|
|
||||||
</g>
|
|
||||||
<!-- langfuse->pg_svc -->
|
|
||||||
<g id="edge10" class="edge">
|
<g id="edge10" class="edge">
|
||||||
<title>langfuse->pg_svc</title>
|
<title>unt_ui->unt_api</title>
|
||||||
<path fill="none" stroke="#4a5568" d="M162,-261.93C162,-247.46 162,-229.62 162,-213.69"/>
|
<path fill="none" stroke="#4a5568" d="M421.75,-313.85C421.62,-301.69 421.45,-286.58 421.31,-273.61"/>
|
||||||
<polygon fill="#4a5568" stroke="#4a5568" points="165.5,-214.02 162,-204.02 158.5,-214.02 165.5,-214.02"/>
|
<polygon fill="#4a5568" stroke="#4a5568" points="424.82,-273.92 421.21,-263.96 417.82,-274 424.82,-273.92"/>
|
||||||
</g>
|
</g>
|
||||||
<!-- langfuse_svc->langfuse -->
|
<!-- unt_api->lf_web -->
|
||||||
<g id="edge9" class="edge">
|
<g id="edge14" class="edge">
|
||||||
<title>langfuse_svc->langfuse</title>
|
<title>unt_api->lf_web</title>
|
||||||
<path fill="none" stroke="#4a5568" d="M162.69,-357.41C162.6,-349.53 162.51,-340.88 162.42,-332.55"/>
|
<path fill="none" stroke="#00c853" stroke-dasharray="1,5" d="M372.64,-232.1C337.77,-222.81 290.61,-207.15 254,-183.59 242.63,-176.28 231.86,-166.23 222.86,-156.56"/>
|
||||||
<polygon fill="#4a5568" stroke="#4a5568" points="165.92,-332.55 162.32,-322.59 158.92,-332.62 165.92,-332.55"/>
|
<polygon fill="#00c853" stroke="#00c853" points="225.71,-154.5 216.44,-149.36 220.49,-159.16 225.71,-154.5"/>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="314.52" y="-194.29" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8892a8">OTLP traces</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- pg -->
|
<!-- unt_api->ext_weather -->
|
||||||
<g id="node8" class="node">
|
|
||||||
<title>pg</title>
|
|
||||||
<path fill="#121829" stroke="#1e2a4a" d="M204.5,-96.81C204.5,-100.83 185.45,-104.09 162,-104.09 138.55,-104.09 119.5,-100.83 119.5,-96.81 119.5,-96.81 119.5,-31.28 119.5,-31.28 119.5,-27.26 138.55,-24 162,-24 185.45,-24 204.5,-27.26 204.5,-31.28 204.5,-31.28 204.5,-96.81 204.5,-96.81"/>
|
|
||||||
<path fill="none" stroke="#1e2a4a" d="M204.5,-96.81C204.5,-92.79 185.45,-89.53 162,-89.53 138.55,-89.53 119.5,-92.79 119.5,-96.81"/>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="162" y="-79.67" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">PostgreSQL</text>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="162" y="-66.92" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">:5432</text>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="162" y="-42.17" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Langfuse data</text>
|
|
||||||
</g>
|
|
||||||
<!-- pg_svc->pg -->
|
|
||||||
<g id="edge11" class="edge">
|
<g id="edge11" class="edge">
|
||||||
<title>pg_svc->pg</title>
|
<title>unt_api->ext_weather</title>
|
||||||
<path fill="none" stroke="#4a5568" d="M162,-140.63C162,-132.92 162,-124.41 162,-115.96"/>
|
<path fill="none" stroke="#00c853" stroke-dasharray="5,2" d="M437.98,-225.52C450.77,-213.62 469.41,-198.77 489,-191.59 519.3,-180.49 604.59,-196.87 634,-183.59 649.26,-176.7 662.63,-163.75 672.58,-151.84"/>
|
||||||
<polygon fill="#4a5568" stroke="#4a5568" points="165.5,-116.07 162,-106.07 158.5,-116.07 165.5,-116.07"/>
|
<polygon fill="#00c853" stroke="#00c853" points="675.12,-154.27 678.55,-144.24 669.62,-149.94 675.12,-154.27"/>
|
||||||
</g>
|
</g>
|
||||||
<!-- ext_kong->ui_svc -->
|
<!-- unt_api->ext_faa -->
|
||||||
|
<g id="edge12" class="edge">
|
||||||
|
<title>unt_api->ext_faa</title>
|
||||||
|
<path fill="none" stroke="#00c853" stroke-dasharray="5,2" d="M430.26,-225.5C437.49,-213.75 448.72,-199.08 463,-191.59 482.55,-181.34 543.16,-195.08 562,-183.59 573.33,-176.68 581.65,-164.72 587.41,-153.45"/>
|
||||||
|
<polygon fill="#00c853" stroke="#00c853" points="590.56,-154.98 591.54,-144.43 584.2,-152.06 590.56,-154.98"/>
|
||||||
|
</g>
|
||||||
|
<!-- unt_api->ext_bedrock -->
|
||||||
<g id="edge13" class="edge">
|
<g id="edge13" class="edge">
|
||||||
<title>ext_kong->ui_svc</title>
|
<title>unt_api->ext_bedrock</title>
|
||||||
<path fill="none" stroke="#4a5568" stroke-dasharray="5,2" d="M640.9,-413.88C621.16,-440.78 594,-485.82 594,-529.97 594,-777.84 594,-777.84 594,-777.84 594,-846.35 383.67,-868.44 257.9,-875.53"/>
|
<path fill="none" stroke="#4a5568" stroke-dasharray="5,2" d="M425.14,-225.54C427.77,-215.45 431.52,-202.61 436,-191.59 440.2,-181.26 445.53,-170.43 450.76,-160.6"/>
|
||||||
<polygon fill="#4a5568" stroke="#4a5568" points="258.06,-872.01 248.27,-876.05 258.44,-879 258.06,-872.01"/>
|
<polygon fill="#4a5568" stroke="#4a5568" points="453.68,-162.56 455.4,-152.11 447.53,-159.21 453.68,-162.56"/>
|
||||||
|
</g>
|
||||||
|
<!-- lf_pg -->
|
||||||
|
<g id="node10" class="node">
|
||||||
|
<title>lf_pg</title>
|
||||||
|
<path fill="#0d1a33" stroke="#1e2a4a" d="M161.62,-57.88C161.62,-60.19 147.45,-62.06 130,-62.06 112.55,-62.06 98.38,-60.19 98.38,-57.88 98.38,-57.88 98.38,-20.19 98.38,-20.19 98.38,-17.88 112.55,-16 130,-16 147.45,-16 161.62,-17.88 161.62,-20.19 161.62,-20.19 161.62,-57.88 161.62,-57.88"/>
|
||||||
|
<path fill="none" stroke="#1e2a4a" d="M161.62,-57.88C161.62,-55.56 147.45,-53.69 130,-53.69 112.55,-53.69 98.38,-55.56 98.38,-57.88"/>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="130" y="-42.28" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Postgres</text>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="130" y="-29.53" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">metadata</text>
|
||||||
|
</g>
|
||||||
|
<!-- lf_web->lf_pg -->
|
||||||
|
<g id="edge19" class="edge">
|
||||||
|
<title>lf_web->lf_pg</title>
|
||||||
|
<path fill="none" stroke="#4a5568" d="M179.78,-101.28C172.25,-92.01 163.39,-81.12 155.25,-71.1"/>
|
||||||
|
<polygon fill="#4a5568" stroke="#4a5568" points="158.01,-68.95 148.99,-63.4 152.58,-73.37 158.01,-68.95"/>
|
||||||
|
</g>
|
||||||
|
<!-- lf_redis -->
|
||||||
|
<g id="node11" class="node">
|
||||||
|
<title>lf_redis</title>
|
||||||
|
<path fill="#0d1a33" stroke="#1e2a4a" d="M262.75,-57.88C262.75,-60.19 244.04,-62.06 221,-62.06 197.96,-62.06 179.25,-60.19 179.25,-57.88 179.25,-57.88 179.25,-20.19 179.25,-20.19 179.25,-17.88 197.96,-16 221,-16 244.04,-16 262.75,-17.88 262.75,-20.19 262.75,-20.19 262.75,-57.88 262.75,-57.88"/>
|
||||||
|
<path fill="none" stroke="#1e2a4a" d="M262.75,-57.88C262.75,-55.56 244.04,-53.69 221,-53.69 197.96,-53.69 179.25,-55.56 179.25,-57.88"/>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="221" y="-42.28" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Redis</text>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="221" y="-29.53" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">queue · cache</text>
|
||||||
|
</g>
|
||||||
|
<!-- lf_web->lf_redis -->
|
||||||
|
<g id="edge16" class="edge">
|
||||||
|
<title>lf_web->lf_redis</title>
|
||||||
|
<path fill="none" stroke="#4a5568" d="M204.16,-101.28C206.51,-92.75 209.24,-82.83 211.8,-73.49"/>
|
||||||
|
<polygon fill="#4a5568" stroke="#4a5568" points="215.14,-74.54 214.42,-63.97 208.39,-72.69 215.14,-74.54"/>
|
||||||
|
</g>
|
||||||
|
<!-- lf_minio -->
|
||||||
|
<g id="node12" class="node">
|
||||||
|
<title>lf_minio</title>
|
||||||
|
<path fill="#0d1a33" stroke="#1e2a4a" d="M80,-57.88C80,-60.19 65.66,-62.06 48,-62.06 30.34,-62.06 16,-60.19 16,-57.88 16,-57.88 16,-20.19 16,-20.19 16,-17.88 30.34,-16 48,-16 65.66,-16 80,-17.88 80,-20.19 80,-20.19 80,-57.88 80,-57.88"/>
|
||||||
|
<path fill="none" stroke="#1e2a4a" d="M80,-57.88C80,-55.56 65.66,-53.69 48,-53.69 30.34,-53.69 16,-55.56 16,-57.88"/>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="48" y="-42.28" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">MinIO</text>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="48" y="-29.53" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">S3 events</text>
|
||||||
|
</g>
|
||||||
|
<!-- lf_web->lf_minio -->
|
||||||
|
<g id="edge20" class="edge">
|
||||||
|
<title>lf_web->lf_minio</title>
|
||||||
|
<path fill="none" stroke="#4a5568" d="M157.8,-101.28C136.92,-89.63 111.41,-75.4 90.24,-63.59"/>
|
||||||
|
<polygon fill="#4a5568" stroke="#4a5568" points="92,-60.57 81.56,-58.75 88.59,-66.68 92,-60.57"/>
|
||||||
|
</g>
|
||||||
|
<!-- lf_worker -->
|
||||||
|
<g id="node8" class="node">
|
||||||
|
<title>lf_worker</title>
|
||||||
|
<polygon fill="#121829" stroke="#1e2a4a" points="365.12,-142.7 262.88,-142.7 262.88,-106.7 365.12,-106.7 365.12,-142.7"/>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="314" y="-127.95" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">langfuse-worker</text>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="314" y="-115.2" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">ClickHouse writer</text>
|
||||||
|
</g>
|
||||||
|
<!-- lf_ch -->
|
||||||
|
<g id="node9" class="node">
|
||||||
|
<title>lf_ch</title>
|
||||||
|
<path fill="#0d1a33" stroke="#1e2a4a" d="M364.75,-57.88C364.75,-60.19 346.04,-62.06 323,-62.06 299.96,-62.06 281.25,-60.19 281.25,-57.88 281.25,-57.88 281.25,-20.19 281.25,-20.19 281.25,-17.88 299.96,-16 323,-16 346.04,-16 364.75,-17.88 364.75,-20.19 364.75,-20.19 364.75,-57.88 364.75,-57.88"/>
|
||||||
|
<path fill="none" stroke="#1e2a4a" d="M364.75,-57.88C364.75,-55.56 346.04,-53.69 323,-53.69 299.96,-53.69 281.25,-55.56 281.25,-57.88"/>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="323" y="-42.28" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">ClickHouse</text>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="323" y="-29.53" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">traces · spans</text>
|
||||||
|
</g>
|
||||||
|
<!-- lf_worker->lf_ch -->
|
||||||
|
<g id="edge18" class="edge">
|
||||||
|
<title>lf_worker->lf_ch</title>
|
||||||
|
<path fill="none" stroke="#4a5568" d="M315.86,-106.37C316.88,-96.92 318.17,-84.89 319.38,-73.68"/>
|
||||||
|
<polygon fill="#4a5568" stroke="#4a5568" points="322.84,-74.26 320.43,-63.94 315.88,-73.51 322.84,-74.26"/>
|
||||||
|
</g>
|
||||||
|
<!-- lf_worker->lf_redis -->
|
||||||
|
<g id="edge17" class="edge">
|
||||||
|
<title>lf_worker->lf_redis</title>
|
||||||
|
<path fill="none" stroke="#4a5568" d="M294.73,-106.37C282.92,-95.74 267.5,-81.86 253.81,-69.55"/>
|
||||||
|
<polygon fill="#4a5568" stroke="#4a5568" points="256.46,-67.23 246.69,-63.14 251.78,-72.43 256.46,-67.23"/>
|
||||||
|
</g>
|
||||||
|
<!-- ext_kong->nginx_edge -->
|
||||||
|
<g id="edge3" class="edge">
|
||||||
|
<title>ext_kong->nginx_edge</title>
|
||||||
|
<path fill="none" stroke="#4a5568" stroke-dasharray="5,2" d="M809.27,-150.83C792.29,-163.15 770.19,-176.78 748,-183.59 735.57,-187.41 523.04,-182.24 514,-191.59 450.61,-257.19 503.77,-314.62 549,-393.84 552.65,-400.23 557.13,-406.41 562,-412.24"/>
|
||||||
|
<polygon fill="#4a5568" stroke="#4a5568" points="559.09,-414.24 568.36,-419.38 564.32,-409.58 559.09,-414.24"/>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="534.04" y="-287.79" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8892a8">X-Gateway-Secret</text>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 21 KiB |
@@ -14,70 +14,67 @@ digraph repo_structure {
|
|||||||
|
|
||||||
mcp [label="mcp_servers/" fillcolor="#121829"]
|
mcp [label="mcp_servers/" fillcolor="#121829"]
|
||||||
agents [label="agents/" fillcolor="#121829"]
|
agents [label="agents/" fillcolor="#121829"]
|
||||||
irrop [label="irrop/" fillcolor="#121829"]
|
|
||||||
api [label="api/" fillcolor="#121829"]
|
api [label="api/" fillcolor="#121829"]
|
||||||
ui_root [label="ui/" fillcolor="#121829"]
|
ui_root [label="ui/" fillcolor="#121829"]
|
||||||
ctrl [label="ctrl/" fillcolor="#121829"]
|
ctrl [label="ctrl/" fillcolor="#121829"]
|
||||||
|
tests [label="tests/" fillcolor="#121829"]
|
||||||
|
woodpecker [label=".woodpecker/" fillcolor="#121829"]
|
||||||
docs [label="docs/" fillcolor="#121829"]
|
docs [label="docs/" fillcolor="#121829"]
|
||||||
|
|
||||||
// MCP subtree
|
// MCP subtree
|
||||||
mcp_shared [label="shared/\nserver.py\ntools/ resources/ prompts/" fillcolor="#0d1a33" shape=box]
|
mcp_shared [label="shared/\nserver.py\ntools.py · resources.py · prompts.py" fillcolor="#0d1a33" shape=box]
|
||||||
mcp_ops [label="ops/\nserver.py\ntools/ resources/ prompts/" fillcolor="#0d1a33" shape=box]
|
mcp_ops [label="ops/\nserver.py\ntools.py · resources.py · prompts.py" fillcolor="#0d1a33" shape=box]
|
||||||
mcp_pax [label="passenger/\nserver.py\ntools/ resources/ prompts/" fillcolor="#0d1a33" shape=box]
|
mcp_pax [label="passenger/\nserver.py\ntools.py · resources.py · prompts.py" fillcolor="#0d1a33" shape=box]
|
||||||
mcp_data [label="data/\nmodels.py\nreal/ (openmeteo, faa)\nmock/\nscenarios/ (4 scenarios)" fillcolor="#0d1a33" shape=box]
|
mcp_llm [label="shared_llm.py\nGroq · Anthropic\nBedrock · OpenAI" fillcolor="#0d1a33" shape=box]
|
||||||
|
mcp_data [label="data/\nmodels.py\nreal/ (openmeteo, faa)\nscenarios/ (4 scenarios)" fillcolor="#0d1a33" shape=box]
|
||||||
|
|
||||||
// Agents subtree
|
// Agents subtree
|
||||||
ag_efhas [label="fce.py\nFCE agent" fillcolor="#1a1a3a" shape=box]
|
ag_fce [label="fce.py\nFCE agent" fillcolor="#1a1a3a" shape=box]
|
||||||
ag_handover [label="handover.py\nHandover agent" fillcolor="#1a1a3a" shape=box]
|
ag_handover [label="handover.py\nHandover agent" fillcolor="#1a1a3a" shape=box]
|
||||||
ag_shared [label="shared/\nmcp_client.py\nllm.py" fillcolor="#1a1a3a" shape=box]
|
ag_shared [label="shared/\nmcp_client.py\nparser.py · tool_runner.py" fillcolor="#1a1a3a" shape=box]
|
||||||
|
|
||||||
// IRROP subtree
|
|
||||||
ir_models [label="models/\nflight, passenger\ncrew, recovery" fillcolor="#1a2a1a" shape=box]
|
|
||||||
ir_rules [label="rules/\nfaa_part117\nrebooking\ncompensation" fillcolor="#1a2a1a" shape=box]
|
|
||||||
ir_pipeline [label="pipeline/\ningest → triage →\nrebook → compensate" fillcolor="#1a2a1a" shape=box]
|
|
||||||
|
|
||||||
// API subtree
|
// API subtree
|
||||||
api_main [label="main.py\nFastAPI + WebSocket" fillcolor="#2a1a1a" shape=box]
|
api_main [label="main.py\nFastAPI + WebSocket\nhealth · runs · Langfuse" fillcolor="#2a1a1a" shape=box]
|
||||||
api_routes [label="routes/\nagents, scenarios, ws" fillcolor="#2a1a1a" shape=box]
|
api_config [label="config.py\nPydantic Settings" fillcolor="#2a1a1a" shape=box]
|
||||||
|
|
||||||
// UI subtree
|
// UI subtree
|
||||||
ui_fw [label="framework/\nsoleprint-ui\n(shared component lib)" fillcolor="#2a2a0d" shape=box]
|
ui_fw [label="framework/\nsoleprint-ui\n(shared component lib)" fillcolor="#2a2a0d" shape=box]
|
||||||
ui_app [label="app/\nVue 3 SPA\npages/ components/\nmars-tokens.css" fillcolor="#2a2a0d" shape=box]
|
ui_app [label="app/\nVue 3 SPA\nconfig.ts (Kong proxy)" fillcolor="#2a2a0d" shape=box]
|
||||||
|
|
||||||
// Ctrl subtree
|
// Ctrl subtree
|
||||||
ctrl_docker [label="Dockerfile.api\nDockerfile.ui\nnginx.conf\ndocker-compose.yml" fillcolor="#1a1a2a" shape=box]
|
ctrl_docker [label="Dockerfile.api\nDockerfile.ui\nnginx.conf" fillcolor="#1a1a2a" shape=box]
|
||||||
ctrl_k8s [label="k8s/\nbase/ overlays/dev/\nkind-config.yaml" fillcolor="#1a1a2a" shape=box]
|
ctrl_k8s [label="k8s/\nbase/ overlays/dev/\nkind-config.yaml" fillcolor="#1a1a2a" shape=box]
|
||||||
ctrl_tilt [label="Tiltfile\ntilt_config.json" fillcolor="#1a1a2a" shape=box]
|
ctrl_edge [label="edge/\ndocker-compose.yml\n(production)" fillcolor="#1a1a2a" shape=box]
|
||||||
|
ctrl_tilt [label="Tiltfile\ndeploy.sh" fillcolor="#1a1a2a" shape=box]
|
||||||
|
|
||||||
// Edges
|
// Edges
|
||||||
root -> mcp
|
root -> mcp
|
||||||
root -> agents
|
root -> agents
|
||||||
root -> irrop
|
|
||||||
root -> api
|
root -> api
|
||||||
root -> ui_root
|
root -> ui_root
|
||||||
root -> ctrl
|
root -> ctrl
|
||||||
|
root -> tests
|
||||||
|
root -> woodpecker
|
||||||
root -> docs
|
root -> docs
|
||||||
|
|
||||||
mcp -> mcp_shared
|
mcp -> mcp_shared
|
||||||
mcp -> mcp_ops
|
mcp -> mcp_ops
|
||||||
mcp -> mcp_pax
|
mcp -> mcp_pax
|
||||||
|
mcp -> mcp_llm
|
||||||
mcp -> mcp_data
|
mcp -> mcp_data
|
||||||
|
|
||||||
agents -> ag_efhas
|
agents -> ag_fce
|
||||||
agents -> ag_handover
|
agents -> ag_handover
|
||||||
agents -> ag_shared
|
agents -> ag_shared
|
||||||
|
|
||||||
irrop -> ir_models
|
|
||||||
irrop -> ir_rules
|
|
||||||
irrop -> ir_pipeline
|
|
||||||
|
|
||||||
api -> api_main
|
api -> api_main
|
||||||
api -> api_routes
|
api -> api_config
|
||||||
|
|
||||||
ui_root -> ui_fw
|
ui_root -> ui_fw
|
||||||
ui_root -> ui_app
|
ui_root -> ui_app
|
||||||
|
|
||||||
ctrl -> ctrl_docker
|
ctrl -> ctrl_docker
|
||||||
ctrl -> ctrl_k8s
|
ctrl -> ctrl_k8s
|
||||||
|
ctrl -> ctrl_edge
|
||||||
ctrl -> ctrl_tilt
|
ctrl -> ctrl_tilt
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,339 +4,334 @@
|
|||||||
<!-- Generated by graphviz version 14.1.2 (0)
|
<!-- Generated by graphviz version 14.1.2 (0)
|
||||||
-->
|
-->
|
||||||
<!-- Title: repo_structure Pages: 1 -->
|
<!-- Title: repo_structure Pages: 1 -->
|
||||||
<svg style="background:#0a0e17" width="4414pt" height="498pt"
|
<svg width="2239pt" height="236pt"
|
||||||
viewBox="0.00 0.00 4414.00 498.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
viewBox="0.00 0.00 2239.00 236.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
<g id="graph0" class="graph" transform="scale(2 2) rotate(0) translate(4 245)">
|
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 232.25)">
|
||||||
<title>repo_structure</title>
|
<title>repo_structure</title>
|
||||||
<polygon fill="#0a0e17" stroke="none" points="-4,4 -4,-245 2203,-245 2203,4 -4,4"/>
|
<polygon fill="#0a0e17" stroke="none" points="-4,4 -4,-232.25 2235.25,-232.25 2235.25,4 -4,4"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1099.5" y="-223.7" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#0066ff">Repository Structure</text>
|
<text xml:space="preserve" text-anchor="middle" x="1115.62" y="-210.95" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#0066ff">Repository Structure</text>
|
||||||
<!-- root -->
|
<!-- root -->
|
||||||
<g id="node1" class="node">
|
<g id="node1" class="node">
|
||||||
<title>root</title>
|
<title>root</title>
|
||||||
<polygon fill="#0066ff" stroke="#1e2a4a" points="1454.75,-215.75 1451.75,-219.75 1430.75,-219.75 1427.75,-215.75 1384,-215.75 1384,-179.75 1454.75,-179.75 1454.75,-215.75"/>
|
<polygon fill="#0066ff" stroke="#1e2a4a" points="1794.75,-203 1791.75,-207 1770.75,-207 1767.75,-203 1724,-203 1724,-167 1794.75,-167 1794.75,-203"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1419.38" y="-194.62" font-family="Helvetica,sans-Serif" font-size="10.00" fill="white">stellar-ops/</text>
|
<text xml:space="preserve" text-anchor="middle" x="1759.38" y="-181.88" font-family="Helvetica,sans-Serif" font-size="10.00" fill="white">stellar-ops/</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- mcp -->
|
<!-- mcp -->
|
||||||
<g id="node2" class="node">
|
<g id="node2" class="node">
|
||||||
<title>mcp</title>
|
<title>mcp</title>
|
||||||
<polygon fill="#121829" stroke="#1e2a4a" points="434,-143.75 431,-147.75 410,-147.75 407,-143.75 352.75,-143.75 352.75,-107.75 434,-107.75 434,-143.75"/>
|
<polygon fill="#121829" stroke="#1e2a4a" points="636,-131 633,-135 612,-135 609,-131 554.75,-131 554.75,-95 636,-95 636,-131"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="393.38" y="-122.62" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">mcp_servers/</text>
|
<text xml:space="preserve" text-anchor="middle" x="595.38" y="-109.88" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">mcp_servers/</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- root->mcp -->
|
<!-- root->mcp -->
|
||||||
<g id="edge1" class="edge">
|
<g id="edge1" class="edge">
|
||||||
<title>root->mcp</title>
|
<title>root->mcp</title>
|
||||||
<path fill="none" stroke="#1e2a4a" d="M1383.76,-194.32C1229.15,-183.77 616.05,-141.94 440.54,-129.97"/>
|
<path fill="none" stroke="#1e2a4a" d="M1723.58,-181.85C1554.39,-171.67 835.03,-128.41 642.78,-116.85"/>
|
||||||
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="440.85,-128.24 435.75,-129.64 440.62,-131.73 440.85,-128.24"/>
|
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="643.04,-115.11 637.94,-116.56 642.83,-118.61 643.04,-115.11"/>
|
||||||
</g>
|
</g>
|
||||||
<!-- agents -->
|
<!-- agents -->
|
||||||
<g id="node3" class="node">
|
<g id="node3" class="node">
|
||||||
<title>agents</title>
|
<title>agents</title>
|
||||||
<polygon fill="#121829" stroke="#1e2a4a" points="843.38,-143.75 840.38,-147.75 819.38,-147.75 816.38,-143.75 789.38,-143.75 789.38,-107.75 843.38,-107.75 843.38,-143.75"/>
|
<polygon fill="#121829" stroke="#1e2a4a" points="1119.38,-131 1116.38,-135 1095.38,-135 1092.38,-131 1065.38,-131 1065.38,-95 1119.38,-95 1119.38,-131"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="816.38" y="-122.62" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">agents/</text>
|
<text xml:space="preserve" text-anchor="middle" x="1092.38" y="-109.88" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">agents/</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- root->agents -->
|
<!-- root->agents -->
|
||||||
<g id="edge2" class="edge">
|
<g id="edge2" class="edge">
|
||||||
<title>root->agents</title>
|
<title>root->agents</title>
|
||||||
<path fill="none" stroke="#1e2a4a" d="M1383.91,-192.63C1276.34,-180.15 954.77,-142.82 849.87,-130.64"/>
|
<path fill="none" stroke="#1e2a4a" d="M1723.51,-180.24C1606.91,-168 1239.52,-129.44 1126.08,-117.54"/>
|
||||||
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="850.24,-128.92 845.07,-130.08 849.84,-132.4 850.24,-128.92"/>
|
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1126.26,-115.8 1121.11,-117.02 1125.9,-119.28 1126.26,-115.8"/>
|
||||||
</g>
|
|
||||||
<!-- irrop -->
|
|
||||||
<g id="node4" class="node">
|
|
||||||
<title>irrop</title>
|
|
||||||
<polygon fill="#121829" stroke="#1e2a4a" points="1177.38,-143.75 1174.38,-147.75 1153.38,-147.75 1150.38,-143.75 1123.38,-143.75 1123.38,-107.75 1177.38,-107.75 1177.38,-143.75"/>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1150.38" y="-122.62" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">irrop/</text>
|
|
||||||
</g>
|
|
||||||
<!-- root->irrop -->
|
|
||||||
<g id="edge3" class="edge">
|
|
||||||
<title>root->irrop</title>
|
|
||||||
<path fill="none" stroke="#1e2a4a" d="M1383.65,-187.45C1331.44,-173.87 1234.95,-148.76 1183.97,-135.49"/>
|
|
||||||
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1184.43,-133.8 1179.15,-134.24 1183.54,-137.19 1184.43,-133.8"/>
|
|
||||||
</g>
|
</g>
|
||||||
<!-- api -->
|
<!-- api -->
|
||||||
<g id="node5" class="node">
|
<g id="node4" class="node">
|
||||||
<title>api</title>
|
<title>api</title>
|
||||||
<polygon fill="#121829" stroke="#1e2a4a" points="1446.38,-143.75 1443.38,-147.75 1422.38,-147.75 1419.38,-143.75 1392.38,-143.75 1392.38,-107.75 1446.38,-107.75 1446.38,-143.75"/>
|
<polygon fill="#121829" stroke="#1e2a4a" points="1473.38,-131 1470.38,-135 1449.38,-135 1446.38,-131 1419.38,-131 1419.38,-95 1473.38,-95 1473.38,-131"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1419.38" y="-122.62" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">api/</text>
|
<text xml:space="preserve" text-anchor="middle" x="1446.38" y="-109.88" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">api/</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- root->api -->
|
<!-- root->api -->
|
||||||
<g id="edge4" class="edge">
|
<g id="edge3" class="edge">
|
||||||
<title>root->api</title>
|
<title>root->api</title>
|
||||||
<path fill="none" stroke="#1e2a4a" d="M1419.38,-179.45C1419.38,-170.63 1419.38,-159.78 1419.38,-150.22"/>
|
<path fill="none" stroke="#1e2a4a" d="M1723.77,-176.04C1662.86,-162.42 1539.48,-134.82 1479.97,-121.51"/>
|
||||||
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1421.13,-150.37 1419.38,-145.37 1417.63,-150.37 1421.13,-150.37"/>
|
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1480.47,-119.83 1475.2,-120.45 1479.7,-123.25 1480.47,-119.83"/>
|
||||||
</g>
|
</g>
|
||||||
<!-- ui_root -->
|
<!-- ui_root -->
|
||||||
<g id="node6" class="node">
|
<g id="node5" class="node">
|
||||||
<title>ui_root</title>
|
<title>ui_root</title>
|
||||||
<polygon fill="#121829" stroke="#1e2a4a" points="1658.38,-143.75 1655.38,-147.75 1634.38,-147.75 1631.38,-143.75 1604.38,-143.75 1604.38,-107.75 1658.38,-107.75 1658.38,-143.75"/>
|
<polygon fill="#121829" stroke="#1e2a4a" points="1750.38,-131 1747.38,-135 1726.38,-135 1723.38,-131 1696.38,-131 1696.38,-95 1750.38,-95 1750.38,-131"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1631.38" y="-122.62" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">ui/</text>
|
<text xml:space="preserve" text-anchor="middle" x="1723.38" y="-109.88" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">ui/</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- root->ui_root -->
|
<!-- root->ui_root -->
|
||||||
<g id="edge5" class="edge">
|
<g id="edge4" class="edge">
|
||||||
<title>root->ui_root</title>
|
<title>root->ui_root</title>
|
||||||
<path fill="none" stroke="#1e2a4a" d="M1454.86,-185.03C1494.69,-171.88 1558.84,-150.7 1597.85,-137.82"/>
|
<path fill="none" stroke="#1e2a4a" d="M1750.48,-166.7C1745.81,-157.63 1740.04,-146.4 1735.02,-136.65"/>
|
||||||
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1598.25,-139.53 1602.45,-136.3 1597.15,-136.21 1598.25,-139.53"/>
|
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1736.71,-136.1 1732.86,-132.45 1733.59,-137.7 1736.71,-136.1"/>
|
||||||
</g>
|
</g>
|
||||||
<!-- ctrl -->
|
<!-- ctrl -->
|
||||||
<g id="node7" class="node">
|
<g id="node6" class="node">
|
||||||
<title>ctrl</title>
|
<title>ctrl</title>
|
||||||
<polygon fill="#121829" stroke="#1e2a4a" points="1932.38,-143.75 1929.38,-147.75 1908.38,-147.75 1905.38,-143.75 1878.38,-143.75 1878.38,-107.75 1932.38,-107.75 1932.38,-143.75"/>
|
<polygon fill="#121829" stroke="#1e2a4a" points="1846.38,-131 1843.38,-135 1822.38,-135 1819.38,-131 1792.38,-131 1792.38,-95 1846.38,-95 1846.38,-131"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1905.38" y="-122.62" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">ctrl/</text>
|
<text xml:space="preserve" text-anchor="middle" x="1819.38" y="-109.88" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">ctrl/</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- root->ctrl -->
|
<!-- root->ctrl -->
|
||||||
<g id="edge6" class="edge">
|
<g id="edge5" class="edge">
|
||||||
<title>root->ctrl</title>
|
<title>root->ctrl</title>
|
||||||
<path fill="none" stroke="#1e2a4a" d="M1455.11,-191.6C1545.68,-178.56 1783.28,-144.34 1871.64,-131.61"/>
|
<path fill="none" stroke="#1e2a4a" d="M1774.21,-166.7C1782.2,-157.37 1792.14,-145.77 1800.66,-135.83"/>
|
||||||
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1871.79,-133.36 1876.49,-130.91 1871.29,-129.89 1871.79,-133.36"/>
|
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1801.8,-137.19 1803.73,-132.25 1799.15,-134.91 1801.8,-137.19"/>
|
||||||
|
</g>
|
||||||
|
<!-- tests -->
|
||||||
|
<g id="node7" class="node">
|
||||||
|
<title>tests</title>
|
||||||
|
<polygon fill="#121829" stroke="#1e2a4a" points="1918.38,-131 1915.38,-135 1894.38,-135 1891.38,-131 1864.38,-131 1864.38,-95 1918.38,-95 1918.38,-131"/>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="1891.38" y="-109.88" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">tests/</text>
|
||||||
|
</g>
|
||||||
|
<!-- root->tests -->
|
||||||
|
<g id="edge6" class="edge">
|
||||||
|
<title>root->tests</title>
|
||||||
|
<path fill="none" stroke="#1e2a4a" d="M1792.34,-166.52C1812.59,-155.78 1838.41,-142.09 1858.62,-131.37"/>
|
||||||
|
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1859.22,-133.03 1862.82,-129.14 1857.58,-129.94 1859.22,-133.03"/>
|
||||||
|
</g>
|
||||||
|
<!-- woodpecker -->
|
||||||
|
<g id="node8" class="node">
|
||||||
|
<title>woodpecker</title>
|
||||||
|
<polygon fill="#121829" stroke="#1e2a4a" points="2016.62,-131 2013.62,-135 1992.62,-135 1989.62,-131 1936.12,-131 1936.12,-95 2016.62,-95 2016.62,-131"/>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="1976.38" y="-109.88" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">.woodpecker/</text>
|
||||||
|
</g>
|
||||||
|
<!-- root->woodpecker -->
|
||||||
|
<g id="edge7" class="edge">
|
||||||
|
<title>root->woodpecker</title>
|
||||||
|
<path fill="none" stroke="#1e2a4a" d="M1795.19,-173.02C1829.27,-162.5 1881.94,-146.05 1927.38,-131 1928.14,-130.75 1928.92,-130.49 1929.7,-130.23"/>
|
||||||
|
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1930.15,-131.92 1934.33,-128.67 1929.03,-128.61 1930.15,-131.92"/>
|
||||||
</g>
|
</g>
|
||||||
<!-- docs -->
|
<!-- docs -->
|
||||||
<g id="node8" class="node">
|
<g id="node9" class="node">
|
||||||
<title>docs</title>
|
<title>docs</title>
|
||||||
<polygon fill="#121829" stroke="#1e2a4a" points="2004.38,-143.75 2001.38,-147.75 1980.38,-147.75 1977.38,-143.75 1950.38,-143.75 1950.38,-107.75 2004.38,-107.75 2004.38,-143.75"/>
|
<polygon fill="#121829" stroke="#1e2a4a" points="2088.38,-131 2085.38,-135 2064.38,-135 2061.38,-131 2034.38,-131 2034.38,-95 2088.38,-95 2088.38,-131"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1977.38" y="-122.62" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">docs/</text>
|
<text xml:space="preserve" text-anchor="middle" x="2061.38" y="-109.88" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">docs/</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- root->docs -->
|
<!-- root->docs -->
|
||||||
<g id="edge7" class="edge">
|
<g id="edge8" class="edge">
|
||||||
<title>root->docs</title>
|
<title>root->docs</title>
|
||||||
<path fill="none" stroke="#1e2a4a" d="M1454.96,-197.25C1540.48,-197.56 1763.66,-193.16 1941.38,-143.75 1942.29,-143.5 1943.21,-143.22 1944.14,-142.92"/>
|
<path fill="none" stroke="#1e2a4a" d="M1794.94,-179.73C1846.63,-172.9 1945.11,-157.5 2025.38,-131 2026.28,-130.7 2027.19,-130.39 2028.1,-130.06"/>
|
||||||
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1944.69,-144.59 1948.8,-141.25 1943.51,-141.29 1944.69,-144.59"/>
|
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="2028.71,-131.7 2032.73,-128.25 2027.44,-128.44 2028.71,-131.7"/>
|
||||||
</g>
|
</g>
|
||||||
<!-- mcp_shared -->
|
<!-- mcp_shared -->
|
||||||
<g id="node9" class="node">
|
<g id="node10" class="node">
|
||||||
<title>mcp_shared</title>
|
<title>mcp_shared</title>
|
||||||
<polygon fill="#0d1a33" stroke="#1e2a4a" points="142.75,-59 0,-59 0,-12.75 142.75,-12.75 142.75,-59"/>
|
<polygon fill="#0d1a33" stroke="#1e2a4a" points="190.75,-52.62 0,-52.62 0,-6.38 190.75,-6.38 190.75,-52.62"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="71.38" y="-45.5" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">shared/</text>
|
<text xml:space="preserve" text-anchor="middle" x="95.38" y="-39.12" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">shared/</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="71.38" y="-32.75" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">server.py</text>
|
<text xml:space="preserve" text-anchor="middle" x="95.38" y="-26.38" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">server.py</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="71.38" y="-20" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">tools/ resources/ prompts/</text>
|
<text xml:space="preserve" text-anchor="middle" x="95.38" y="-13.62" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">tools.py · resources.py · prompts.py</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- mcp->mcp_shared -->
|
<!-- mcp->mcp_shared -->
|
||||||
<g id="edge8" class="edge">
|
<g id="edge9" class="edge">
|
||||||
<title>mcp->mcp_shared</title>
|
<title>mcp->mcp_shared</title>
|
||||||
<path fill="none" stroke="#1e2a4a" d="M352.67,-118.24C304.25,-109.93 221.29,-93.94 152.38,-71.75 143.53,-68.9 134.32,-65.44 125.43,-61.82"/>
|
<path fill="none" stroke="#1e2a4a" d="M554.42,-108.3C482.36,-101.39 328.39,-84.84 200.38,-59 193.85,-57.68 187.14,-56.19 180.41,-54.59"/>
|
||||||
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="126.32,-60.3 121.03,-60.01 124.98,-63.53 126.32,-60.3"/>
|
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="180.97,-52.93 175.7,-53.45 180.15,-56.33 180.97,-52.93"/>
|
||||||
</g>
|
</g>
|
||||||
<!-- mcp_ops -->
|
<!-- mcp_ops -->
|
||||||
<g id="node10" class="node">
|
<g id="node11" class="node">
|
||||||
<title>mcp_ops</title>
|
<title>mcp_ops</title>
|
||||||
<polygon fill="#0d1a33" stroke="#1e2a4a" points="303.75,-59 161,-59 161,-12.75 303.75,-12.75 303.75,-59"/>
|
<polygon fill="#0d1a33" stroke="#1e2a4a" points="399.75,-52.62 209,-52.62 209,-6.38 399.75,-6.38 399.75,-52.62"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="232.38" y="-45.5" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">ops/</text>
|
<text xml:space="preserve" text-anchor="middle" x="304.38" y="-39.12" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">ops/</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="232.38" y="-32.75" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">server.py</text>
|
<text xml:space="preserve" text-anchor="middle" x="304.38" y="-26.38" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">server.py</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="232.38" y="-20" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">tools/ resources/ prompts/</text>
|
<text xml:space="preserve" text-anchor="middle" x="304.38" y="-13.62" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">tools.py · resources.py · prompts.py</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- mcp->mcp_ops -->
|
<!-- mcp->mcp_ops -->
|
||||||
<g id="edge9" class="edge">
|
<g id="edge10" class="edge">
|
||||||
<title>mcp->mcp_ops</title>
|
<title>mcp->mcp_ops</title>
|
||||||
<path fill="none" stroke="#1e2a4a" d="M361.57,-107.39C338.04,-94.55 305.62,-76.85 279.15,-62.4"/>
|
<path fill="none" stroke="#1e2a4a" d="M554.3,-100.5C512.14,-88.69 445.24,-69.95 391.27,-54.84"/>
|
||||||
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="280.15,-60.96 274.92,-60.1 278.47,-64.03 280.15,-60.96"/>
|
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="391.83,-53.18 386.55,-53.51 390.89,-56.55 391.83,-53.18"/>
|
||||||
</g>
|
</g>
|
||||||
<!-- mcp_pax -->
|
<!-- mcp_pax -->
|
||||||
<g id="node11" class="node">
|
<g id="node12" class="node">
|
||||||
<title>mcp_pax</title>
|
<title>mcp_pax</title>
|
||||||
<polygon fill="#0d1a33" stroke="#1e2a4a" points="464.75,-59 322,-59 322,-12.75 464.75,-12.75 464.75,-59"/>
|
<polygon fill="#0d1a33" stroke="#1e2a4a" points="608.75,-52.62 418,-52.62 418,-6.38 608.75,-6.38 608.75,-52.62"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="393.38" y="-45.5" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">passenger/</text>
|
<text xml:space="preserve" text-anchor="middle" x="513.38" y="-39.12" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">passenger/</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="393.38" y="-32.75" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">server.py</text>
|
<text xml:space="preserve" text-anchor="middle" x="513.38" y="-26.38" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">server.py</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="393.38" y="-20" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">tools/ resources/ prompts/</text>
|
<text xml:space="preserve" text-anchor="middle" x="513.38" y="-13.62" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">tools.py · resources.py · prompts.py</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- mcp->mcp_pax -->
|
<!-- mcp->mcp_pax -->
|
||||||
<g id="edge10" class="edge">
|
<g id="edge11" class="edge">
|
||||||
<title>mcp->mcp_pax</title>
|
<title>mcp->mcp_pax</title>
|
||||||
<path fill="none" stroke="#1e2a4a" d="M393.38,-107.39C393.38,-95.42 393.38,-79.23 393.38,-65.38"/>
|
<path fill="none" stroke="#1e2a4a" d="M577.98,-94.72C567.1,-83.9 552.84,-69.73 540.49,-57.45"/>
|
||||||
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="395.13,-65.72 393.38,-60.72 391.63,-65.72 395.13,-65.72"/>
|
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="541.89,-56.38 537.11,-54.09 539.43,-58.86 541.89,-56.38"/>
|
||||||
|
</g>
|
||||||
|
<!-- mcp_llm -->
|
||||||
|
<g id="node13" class="node">
|
||||||
|
<title>mcp_llm</title>
|
||||||
|
<polygon fill="#0d1a33" stroke="#1e2a4a" points="726.38,-52.62 626.38,-52.62 626.38,-6.38 726.38,-6.38 726.38,-52.62"/>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="676.38" y="-39.12" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">shared_llm.py</text>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="676.38" y="-26.38" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Groq · Anthropic</text>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="676.38" y="-13.62" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Bedrock · OpenAI</text>
|
||||||
|
</g>
|
||||||
|
<!-- mcp->mcp_llm -->
|
||||||
|
<g id="edge12" class="edge">
|
||||||
|
<title>mcp->mcp_llm</title>
|
||||||
|
<path fill="none" stroke="#1e2a4a" d="M612.55,-94.72C623.31,-83.9 637.39,-69.73 649.59,-57.45"/>
|
||||||
|
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="650.64,-58.88 652.92,-54.1 648.15,-56.41 650.64,-58.88"/>
|
||||||
</g>
|
</g>
|
||||||
<!-- mcp_data -->
|
<!-- mcp_data -->
|
||||||
<g id="node12" class="node">
|
<g id="node14" class="node">
|
||||||
<title>mcp_data</title>
|
<title>mcp_data</title>
|
||||||
<polygon fill="#0d1a33" stroke="#1e2a4a" points="614.12,-71.75 482.62,-71.75 482.62,0 614.12,0 614.12,-71.75"/>
|
<polygon fill="#0d1a33" stroke="#1e2a4a" points="876.12,-59 744.62,-59 744.62,0 876.12,0 876.12,-59"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="548.38" y="-58.25" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">data/</text>
|
<text xml:space="preserve" text-anchor="middle" x="810.38" y="-45.5" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">data/</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="548.38" y="-45.5" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">models.py</text>
|
<text xml:space="preserve" text-anchor="middle" x="810.38" y="-32.75" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">models.py</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="548.38" y="-32.75" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">real/ (openmeteo, faa)</text>
|
<text xml:space="preserve" text-anchor="middle" x="810.38" y="-20" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">real/ (openmeteo, faa)</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="548.38" y="-20" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">mock/</text>
|
<text xml:space="preserve" text-anchor="middle" x="810.38" y="-7.25" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">scenarios/ (4 scenarios)</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="548.38" y="-7.25" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">scenarios/ (4 scenarios)</text>
|
|
||||||
</g>
|
</g>
|
||||||
<!-- mcp->mcp_data -->
|
<!-- mcp->mcp_data -->
|
||||||
<g id="edge11" class="edge">
|
<g id="edge13" class="edge">
|
||||||
<title>mcp->mcp_data</title>
|
<title>mcp->mcp_data</title>
|
||||||
<path fill="none" stroke="#1e2a4a" d="M424,-107.39C440.21,-98.2 460.8,-86.52 480.54,-75.33"/>
|
<path fill="none" stroke="#1e2a4a" d="M636.42,-96.48C664.33,-85.92 702.08,-71.63 735.38,-59 736.4,-58.61 737.44,-58.22 738.49,-57.82"/>
|
||||||
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="481.28,-76.93 484.77,-72.94 479.55,-73.88 481.28,-76.93"/>
|
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="739.06,-59.47 743.11,-56.06 737.82,-56.2 739.06,-59.47"/>
|
||||||
</g>
|
</g>
|
||||||
<!-- ag_efhas -->
|
<!-- ag_fce -->
|
||||||
<g id="node13" class="node">
|
<g id="node15" class="node">
|
||||||
<title>ag_efhas</title>
|
<title>ag_fce</title>
|
||||||
<polygon fill="#1a1a3a" stroke="#1e2a4a" points="698.12,-53.88 632.62,-53.88 632.62,-17.88 698.12,-17.88 698.12,-53.88"/>
|
<polygon fill="#1a1a3a" stroke="#1e2a4a" points="960.12,-47.5 894.62,-47.5 894.62,-11.5 960.12,-11.5 960.12,-47.5"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="665.38" y="-39.12" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">fce.py</text>
|
<text xml:space="preserve" text-anchor="middle" x="927.38" y="-32.75" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">fce.py</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="665.38" y="-26.38" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">FCE agent</text>
|
<text xml:space="preserve" text-anchor="middle" x="927.38" y="-20" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">FCE agent</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- agents->ag_efhas -->
|
<!-- agents->ag_fce -->
|
||||||
<g id="edge12" class="edge">
|
<g id="edge14" class="edge">
|
||||||
<title>agents->ag_efhas</title>
|
<title>agents->ag_fce</title>
|
||||||
<path fill="none" stroke="#1e2a4a" d="M788.98,-113.62C766.33,-103.91 733.72,-88.74 707.38,-71.75 701.15,-67.74 694.82,-62.93 689.02,-58.18"/>
|
<path fill="none" stroke="#1e2a4a" d="M1065.29,-102.04C1039.9,-92.31 1001.18,-76.44 969.38,-59 965.14,-56.68 960.79,-54.04 956.57,-51.33"/>
|
||||||
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="690.4,-57.06 685.44,-55.19 688.16,-59.74 690.4,-57.06"/>
|
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="957.72,-49.99 952.58,-48.71 955.8,-52.92 957.72,-49.99"/>
|
||||||
</g>
|
</g>
|
||||||
<!-- ag_handover -->
|
<!-- ag_handover -->
|
||||||
<g id="node14" class="node">
|
<g id="node16" class="node">
|
||||||
<title>ag_handover</title>
|
<title>ag_handover</title>
|
||||||
<polygon fill="#1a1a3a" stroke="#1e2a4a" points="810.38,-53.88 716.38,-53.88 716.38,-17.88 810.38,-17.88 810.38,-53.88"/>
|
<polygon fill="#1a1a3a" stroke="#1e2a4a" points="1072.38,-47.5 978.38,-47.5 978.38,-11.5 1072.38,-11.5 1072.38,-47.5"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="763.38" y="-39.12" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">handover.py</text>
|
<text xml:space="preserve" text-anchor="middle" x="1025.38" y="-32.75" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">handover.py</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="763.38" y="-26.38" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Handover agent</text>
|
<text xml:space="preserve" text-anchor="middle" x="1025.38" y="-20" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Handover agent</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- agents->ag_handover -->
|
<!-- agents->ag_handover -->
|
||||||
<g id="edge13" class="edge">
|
<g id="edge15" class="edge">
|
||||||
<title>agents->ag_handover</title>
|
<title>agents->ag_handover</title>
|
||||||
<path fill="none" stroke="#1e2a4a" d="M805.9,-107.39C797.63,-93.67 786.01,-74.41 777.01,-59.48"/>
|
<path fill="none" stroke="#1e2a4a" d="M1078.17,-94.72C1068.04,-82.4 1054.35,-65.74 1043.44,-52.48"/>
|
||||||
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="778.69,-58.87 774.61,-55.5 775.69,-60.68 778.69,-58.87"/>
|
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1045.05,-51.68 1040.52,-48.93 1042.35,-53.9 1045.05,-51.68"/>
|
||||||
</g>
|
</g>
|
||||||
<!-- ag_shared -->
|
<!-- ag_shared -->
|
||||||
<g id="node15" class="node">
|
<g id="node17" class="node">
|
||||||
<title>ag_shared</title>
|
<title>ag_shared</title>
|
||||||
<polygon fill="#1a1a3a" stroke="#1e2a4a" points="912.5,-59 828.25,-59 828.25,-12.75 912.5,-12.75 912.5,-59"/>
|
<polygon fill="#1a1a3a" stroke="#1e2a4a" points="1230.25,-52.62 1090.5,-52.62 1090.5,-6.38 1230.25,-6.38 1230.25,-52.62"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="870.38" y="-45.5" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">shared/</text>
|
<text xml:space="preserve" text-anchor="middle" x="1160.38" y="-39.12" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">shared/</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="870.38" y="-32.75" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">mcp_client.py</text>
|
<text xml:space="preserve" text-anchor="middle" x="1160.38" y="-26.38" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">mcp_client.py</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="870.38" y="-20" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">llm.py</text>
|
<text xml:space="preserve" text-anchor="middle" x="1160.38" y="-13.62" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">parser.py · tool_runner.py</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- agents->ag_shared -->
|
<!-- agents->ag_shared -->
|
||||||
<g id="edge14" class="edge">
|
|
||||||
<title>agents->ag_shared</title>
|
|
||||||
<path fill="none" stroke="#1e2a4a" d="M827.04,-107.39C834.53,-95.2 844.71,-78.64 853.32,-64.64"/>
|
|
||||||
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="854.73,-65.68 855.86,-60.5 851.75,-63.84 854.73,-65.68"/>
|
|
||||||
</g>
|
|
||||||
<!-- ir_models -->
|
|
||||||
<g id="node16" class="node">
|
|
||||||
<title>ir_models</title>
|
|
||||||
<polygon fill="#1a2a1a" stroke="#1e2a4a" points="1027.88,-59 930.88,-59 930.88,-12.75 1027.88,-12.75 1027.88,-59"/>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="979.38" y="-45.5" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">models/</text>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="979.38" y="-32.75" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">flight, passenger</text>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="979.38" y="-20" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">crew, recovery</text>
|
|
||||||
</g>
|
|
||||||
<!-- irrop->ir_models -->
|
|
||||||
<g id="edge15" class="edge">
|
|
||||||
<title>irrop->ir_models</title>
|
|
||||||
<path fill="none" stroke="#1e2a4a" d="M1123.23,-113.17C1099.86,-102.96 1065.42,-87.32 1036.38,-71.75 1031.08,-68.91 1025.6,-65.8 1020.22,-62.63"/>
|
|
||||||
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1021.38,-61.29 1016.19,-60.23 1019.59,-64.29 1021.38,-61.29"/>
|
|
||||||
</g>
|
|
||||||
<!-- ir_rules -->
|
|
||||||
<g id="node17" class="node">
|
|
||||||
<title>ir_rules</title>
|
|
||||||
<polygon fill="#1a2a1a" stroke="#1e2a4a" points="1130.88,-65.38 1045.88,-65.38 1045.88,-6.38 1130.88,-6.38 1130.88,-65.38"/>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1088.38" y="-51.88" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">rules/</text>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1088.38" y="-39.12" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">faa_part117</text>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1088.38" y="-26.38" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">rebooking</text>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1088.38" y="-13.62" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">compensation</text>
|
|
||||||
</g>
|
|
||||||
<!-- irrop->ir_rules -->
|
|
||||||
<g id="edge16" class="edge">
|
<g id="edge16" class="edge">
|
||||||
<title>irrop->ir_rules</title>
|
<title>agents->ag_shared</title>
|
||||||
<path fill="none" stroke="#1e2a4a" d="M1138.13,-107.39C1130.78,-96.97 1121.18,-83.36 1112.37,-70.88"/>
|
<path fill="none" stroke="#1e2a4a" d="M1106.8,-94.72C1115.74,-83.99 1127.44,-69.98 1137.62,-57.78"/>
|
||||||
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1113.84,-69.93 1109.53,-66.85 1110.98,-71.95 1113.84,-69.93"/>
|
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1138.75,-59.15 1140.61,-54.19 1136.06,-56.91 1138.75,-59.15"/>
|
||||||
</g>
|
|
||||||
<!-- ir_pipeline -->
|
|
||||||
<g id="node18" class="node">
|
|
||||||
<title>ir_pipeline</title>
|
|
||||||
<polygon fill="#1a2a1a" stroke="#1e2a4a" points="1273.38,-59 1149.38,-59 1149.38,-12.75 1273.38,-12.75 1273.38,-59"/>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1211.38" y="-45.5" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">pipeline/</text>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1211.38" y="-32.75" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">ingest → triage →</text>
|
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1211.38" y="-20" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">rebook → compensate</text>
|
|
||||||
</g>
|
|
||||||
<!-- irrop->ir_pipeline -->
|
|
||||||
<g id="edge17" class="edge">
|
|
||||||
<title>irrop->ir_pipeline</title>
|
|
||||||
<path fill="none" stroke="#1e2a4a" d="M1162.43,-107.39C1170.96,-95.09 1182.58,-78.35 1192.36,-64.27"/>
|
|
||||||
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1193.59,-65.56 1195.01,-60.45 1190.72,-63.56 1193.59,-65.56"/>
|
|
||||||
</g>
|
</g>
|
||||||
<!-- api_main -->
|
<!-- api_main -->
|
||||||
<g id="node19" class="node">
|
<g id="node18" class="node">
|
||||||
<title>api_main</title>
|
<title>api_main</title>
|
||||||
<polygon fill="#2a1a1a" stroke="#1e2a4a" points="1409.75,-53.88 1291,-53.88 1291,-17.88 1409.75,-17.88 1409.75,-53.88"/>
|
<polygon fill="#2a1a1a" stroke="#1e2a4a" points="1378.38,-52.62 1248.38,-52.62 1248.38,-6.38 1378.38,-6.38 1378.38,-52.62"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1350.38" y="-39.12" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">main.py</text>
|
<text xml:space="preserve" text-anchor="middle" x="1313.38" y="-39.12" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">main.py</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1350.38" y="-26.38" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">FastAPI + WebSocket</text>
|
<text xml:space="preserve" text-anchor="middle" x="1313.38" y="-26.38" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">FastAPI + WebSocket</text>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="1313.38" y="-13.62" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">health · runs · Langfuse</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- api->api_main -->
|
<!-- api->api_main -->
|
||||||
<g id="edge18" class="edge">
|
<g id="edge17" class="edge">
|
||||||
<title>api->api_main</title>
|
<title>api->api_main</title>
|
||||||
<path fill="none" stroke="#1e2a4a" d="M1405.74,-107.39C1394.87,-93.55 1379.58,-74.07 1367.82,-59.09"/>
|
<path fill="none" stroke="#1e2a4a" d="M1419.14,-95.31C1400.86,-84.11 1376.42,-69.13 1355.63,-56.4"/>
|
||||||
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1369.38,-58.24 1364.91,-55.39 1366.63,-60.4 1369.38,-58.24"/>
|
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1356.62,-54.95 1351.45,-53.83 1354.8,-57.93 1356.62,-54.95"/>
|
||||||
</g>
|
</g>
|
||||||
<!-- api_routes -->
|
<!-- api_config -->
|
||||||
<g id="node20" class="node">
|
<g id="node19" class="node">
|
||||||
<title>api_routes</title>
|
<title>api_config</title>
|
||||||
<polygon fill="#2a1a1a" stroke="#1e2a4a" points="1548.88,-53.88 1427.88,-53.88 1427.88,-17.88 1548.88,-17.88 1548.88,-53.88"/>
|
<polygon fill="#2a1a1a" stroke="#1e2a4a" points="1496.75,-47.5 1396,-47.5 1396,-11.5 1496.75,-11.5 1496.75,-47.5"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1488.38" y="-39.12" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">routes/</text>
|
<text xml:space="preserve" text-anchor="middle" x="1446.38" y="-32.75" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">config.py</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1488.38" y="-26.38" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">agents, scenarios, ws</text>
|
<text xml:space="preserve" text-anchor="middle" x="1446.38" y="-20" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Pydantic Settings</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- api->api_routes -->
|
<!-- api->api_config -->
|
||||||
<g id="edge19" class="edge">
|
<g id="edge18" class="edge">
|
||||||
<title>api->api_routes</title>
|
<title>api->api_config</title>
|
||||||
<path fill="none" stroke="#1e2a4a" d="M1433.01,-107.39C1443.88,-93.55 1459.17,-74.07 1470.93,-59.09"/>
|
<path fill="none" stroke="#1e2a4a" d="M1446.38,-94.72C1446.38,-82.94 1446.38,-67.19 1446.38,-54.24"/>
|
||||||
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1472.12,-60.4 1473.84,-55.39 1469.37,-58.24 1472.12,-60.4"/>
|
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1448.13,-54.27 1446.38,-49.27 1444.63,-54.27 1448.13,-54.27"/>
|
||||||
</g>
|
</g>
|
||||||
<!-- ui_fw -->
|
<!-- ui_fw -->
|
||||||
<g id="node21" class="node">
|
<g id="node20" class="node">
|
||||||
<title>ui_fw</title>
|
<title>ui_fw</title>
|
||||||
<polygon fill="#2a2a0d" stroke="#1e2a4a" points="1696,-59 1566.75,-59 1566.75,-12.75 1696,-12.75 1696,-59"/>
|
<polygon fill="#2a2a0d" stroke="#1e2a4a" points="1644,-52.62 1514.75,-52.62 1514.75,-6.38 1644,-6.38 1644,-52.62"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1631.38" y="-45.5" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">framework/</text>
|
<text xml:space="preserve" text-anchor="middle" x="1579.38" y="-39.12" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">framework/</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1631.38" y="-32.75" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">soleprint-ui</text>
|
<text xml:space="preserve" text-anchor="middle" x="1579.38" y="-26.38" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">soleprint-ui</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1631.38" y="-20" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">(shared component lib)</text>
|
<text xml:space="preserve" text-anchor="middle" x="1579.38" y="-13.62" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">(shared component lib)</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- ui_root->ui_fw -->
|
<!-- ui_root->ui_fw -->
|
||||||
<g id="edge20" class="edge">
|
<g id="edge19" class="edge">
|
||||||
<title>ui_root->ui_fw</title>
|
<title>ui_root->ui_fw</title>
|
||||||
<path fill="none" stroke="#1e2a4a" d="M1631.38,-107.39C1631.38,-95.42 1631.38,-79.23 1631.38,-65.38"/>
|
<path fill="none" stroke="#1e2a4a" d="M1695.95,-96.48C1675.86,-85.11 1648.12,-69.41 1624.75,-56.18"/>
|
||||||
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1633.13,-65.72 1631.38,-60.72 1629.63,-65.72 1633.13,-65.72"/>
|
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1625.75,-54.73 1620.53,-53.79 1624.02,-57.78 1625.75,-54.73"/>
|
||||||
</g>
|
</g>
|
||||||
<!-- ui_app -->
|
<!-- ui_app -->
|
||||||
<g id="node22" class="node">
|
<g id="node21" class="node">
|
||||||
<title>ui_app</title>
|
<title>ui_app</title>
|
||||||
<polygon fill="#2a2a0d" stroke="#1e2a4a" points="1828.5,-65.38 1714.25,-65.38 1714.25,-6.38 1828.5,-6.38 1828.5,-65.38"/>
|
<polygon fill="#2a2a0d" stroke="#1e2a4a" points="1784.62,-52.62 1662.12,-52.62 1662.12,-6.38 1784.62,-6.38 1784.62,-52.62"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1771.38" y="-51.88" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">app/</text>
|
<text xml:space="preserve" text-anchor="middle" x="1723.38" y="-39.12" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">app/</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1771.38" y="-39.12" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Vue 3 SPA</text>
|
<text xml:space="preserve" text-anchor="middle" x="1723.38" y="-26.38" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Vue 3 SPA</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1771.38" y="-26.38" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">pages/ components/</text>
|
<text xml:space="preserve" text-anchor="middle" x="1723.38" y="-13.62" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">config.ts (Kong proxy)</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1771.38" y="-13.62" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">mars-tokens.css</text>
|
|
||||||
</g>
|
</g>
|
||||||
<!-- ui_root->ui_app -->
|
<!-- ui_root->ui_app -->
|
||||||
<g id="edge21" class="edge">
|
<g id="edge20" class="edge">
|
||||||
<title>ui_root->ui_app</title>
|
<title>ui_root->ui_app</title>
|
||||||
<path fill="none" stroke="#1e2a4a" d="M1658.7,-107.6C1676.09,-96.69 1699.15,-82.21 1719.88,-69.2"/>
|
<path fill="none" stroke="#1e2a4a" d="M1723.38,-94.72C1723.38,-84.47 1723.38,-71.21 1723.38,-59.41"/>
|
||||||
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1720.79,-70.69 1724.1,-66.55 1718.93,-67.73 1720.79,-70.69"/>
|
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1725.13,-59.54 1723.38,-54.54 1721.63,-59.54 1725.13,-59.54"/>
|
||||||
</g>
|
</g>
|
||||||
<!-- ctrl_docker -->
|
<!-- ctrl_docker -->
|
||||||
<g id="node23" class="node">
|
<g id="node22" class="node">
|
||||||
<title>ctrl_docker</title>
|
<title>ctrl_docker</title>
|
||||||
<polygon fill="#1a1a2a" stroke="#1e2a4a" points="1964.38,-65.38 1846.38,-65.38 1846.38,-6.38 1964.38,-6.38 1964.38,-65.38"/>
|
<polygon fill="#1a1a2a" stroke="#1e2a4a" points="1885.75,-52.62 1803,-52.62 1803,-6.38 1885.75,-6.38 1885.75,-52.62"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1905.38" y="-51.88" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Dockerfile.api</text>
|
<text xml:space="preserve" text-anchor="middle" x="1844.38" y="-39.12" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Dockerfile.api</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1905.38" y="-39.12" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Dockerfile.ui</text>
|
<text xml:space="preserve" text-anchor="middle" x="1844.38" y="-26.38" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Dockerfile.ui</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1905.38" y="-26.38" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">nginx.conf</text>
|
<text xml:space="preserve" text-anchor="middle" x="1844.38" y="-13.62" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">nginx.conf</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="1905.38" y="-13.62" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">docker-compose.yml</text>
|
|
||||||
</g>
|
</g>
|
||||||
<!-- ctrl->ctrl_docker -->
|
<!-- ctrl->ctrl_docker -->
|
||||||
<g id="edge22" class="edge">
|
<g id="edge21" class="edge">
|
||||||
<title>ctrl->ctrl_docker</title>
|
<title>ctrl->ctrl_docker</title>
|
||||||
<path fill="none" stroke="#1e2a4a" d="M1905.38,-107.39C1905.38,-97.25 1905.38,-84.09 1905.38,-71.89"/>
|
<path fill="none" stroke="#1e2a4a" d="M1824.68,-94.72C1827.85,-84.37 1831.96,-70.96 1835.61,-59.08"/>
|
||||||
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1907.13,-72.13 1905.38,-67.13 1903.63,-72.13 1907.13,-72.13"/>
|
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1837.23,-59.77 1837.02,-54.47 1833.88,-58.74 1837.23,-59.77"/>
|
||||||
</g>
|
</g>
|
||||||
<!-- ctrl_k8s -->
|
<!-- ctrl_k8s -->
|
||||||
<g id="node24" class="node">
|
<g id="node23" class="node">
|
||||||
<title>ctrl_k8s</title>
|
<title>ctrl_k8s</title>
|
||||||
<polygon fill="#1a1a2a" stroke="#1e2a4a" points="2094,-59 1982.75,-59 1982.75,-12.75 2094,-12.75 2094,-59"/>
|
<polygon fill="#1a1a2a" stroke="#1e2a4a" points="2015,-52.62 1903.75,-52.62 1903.75,-6.38 2015,-6.38 2015,-52.62"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="2038.38" y="-45.5" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">k8s/</text>
|
<text xml:space="preserve" text-anchor="middle" x="1959.38" y="-39.12" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">k8s/</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="2038.38" y="-32.75" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">base/ overlays/dev/</text>
|
<text xml:space="preserve" text-anchor="middle" x="1959.38" y="-26.38" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">base/ overlays/dev/</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="2038.38" y="-20" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">kind-config.yaml</text>
|
<text xml:space="preserve" text-anchor="middle" x="1959.38" y="-13.62" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">kind-config.yaml</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- ctrl->ctrl_k8s -->
|
<!-- ctrl->ctrl_k8s -->
|
||||||
<g id="edge23" class="edge">
|
<g id="edge22" class="edge">
|
||||||
<title>ctrl->ctrl_k8s</title>
|
<title>ctrl->ctrl_k8s</title>
|
||||||
<path fill="none" stroke="#1e2a4a" d="M1931.65,-107.39C1950.91,-94.66 1977.39,-77.17 1999.15,-62.79"/>
|
<path fill="none" stroke="#1e2a4a" d="M1846.7,-96.09C1866.14,-84.78 1892.68,-69.33 1915.12,-56.26"/>
|
||||||
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="2000.1,-64.26 2003.31,-60.04 1998.17,-61.34 2000.1,-64.26"/>
|
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="1915.98,-57.79 1919.42,-53.76 1914.22,-54.76 1915.98,-57.79"/>
|
||||||
|
</g>
|
||||||
|
<!-- ctrl_edge -->
|
||||||
|
<g id="node24" class="node">
|
||||||
|
<title>ctrl_edge</title>
|
||||||
|
<polygon fill="#1a1a2a" stroke="#1e2a4a" points="2151.38,-52.62 2033.38,-52.62 2033.38,-6.38 2151.38,-6.38 2151.38,-52.62"/>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="2092.38" y="-39.12" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">edge/</text>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="2092.38" y="-26.38" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">docker-compose.yml</text>
|
||||||
|
<text xml:space="preserve" text-anchor="middle" x="2092.38" y="-13.62" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">(production)</text>
|
||||||
|
</g>
|
||||||
|
<!-- ctrl->ctrl_edge -->
|
||||||
|
<g id="edge23" class="edge">
|
||||||
|
<title>ctrl->ctrl_edge</title>
|
||||||
|
<path fill="none" stroke="#1e2a4a" d="M1846.62,-98.33C1849.54,-97.11 1852.49,-95.97 1855.38,-95 1928.14,-70.44 1951.09,-81.94 2024.38,-59 2028.06,-57.85 2031.83,-56.57 2035.6,-55.21"/>
|
||||||
|
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="2036.02,-56.92 2040.1,-53.54 2034.8,-53.64 2036.02,-56.92"/>
|
||||||
</g>
|
</g>
|
||||||
<!-- ctrl_tilt -->
|
<!-- ctrl_tilt -->
|
||||||
<g id="node25" class="node">
|
<g id="node25" class="node">
|
||||||
<title>ctrl_tilt</title>
|
<title>ctrl_tilt</title>
|
||||||
<polygon fill="#1a1a2a" stroke="#1e2a4a" points="2199,-53.88 2111.75,-53.88 2111.75,-17.88 2199,-17.88 2199,-53.88"/>
|
<polygon fill="#1a1a2a" stroke="#1e2a4a" points="2231.25,-47.5 2169.5,-47.5 2169.5,-11.5 2231.25,-11.5 2231.25,-47.5"/>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="2155.38" y="-39.12" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Tiltfile</text>
|
<text xml:space="preserve" text-anchor="middle" x="2200.38" y="-32.75" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">Tiltfile</text>
|
||||||
<text xml:space="preserve" text-anchor="middle" x="2155.38" y="-26.38" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">tilt_config.json</text>
|
<text xml:space="preserve" text-anchor="middle" x="2200.38" y="-20" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#e8eaf0">deploy.sh</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- ctrl->ctrl_tilt -->
|
<!-- ctrl->ctrl_tilt -->
|
||||||
<g id="edge24" class="edge">
|
<g id="edge24" class="edge">
|
||||||
<title>ctrl->ctrl_tilt</title>
|
<title>ctrl->ctrl_tilt</title>
|
||||||
<path fill="none" stroke="#1e2a4a" d="M1932.63,-111.11C1935.55,-109.88 1938.5,-108.74 1941.38,-107.75 2011.15,-83.86 2035.58,-100.79 2103.38,-71.75 2111.9,-68.1 2120.52,-63.01 2128.22,-57.84"/>
|
<path fill="none" stroke="#1e2a4a" d="M1846.54,-98.06C1849.47,-96.89 1852.45,-95.84 1855.38,-95 1986.58,-57.37 2033.03,-108.14 2160.38,-59 2165.41,-57.06 2170.39,-54.34 2175.05,-51.34"/>
|
||||||
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="2129.03,-59.41 2132.15,-55.13 2127.04,-56.53 2129.03,-59.41"/>
|
<polygon fill="#1e2a4a" stroke="#1e2a4a" points="2175.96,-52.84 2179.1,-48.58 2173.98,-49.95 2175.96,-52.84"/>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 22 KiB |
214
docs/index.html
214
docs/index.html
@@ -168,6 +168,66 @@
|
|||||||
.t-pax { color: #00c853; font-weight: 500; }
|
.t-pax { color: #00c853; font-weight: 500; }
|
||||||
.t-live { color: #00c853; }
|
.t-live { color: #00c853; }
|
||||||
.t-comment { color: #4a5568; }
|
.t-comment { color: #4a5568; }
|
||||||
|
|
||||||
|
/* Prose sections (walkthrough, design) */
|
||||||
|
.graph-section h3 {
|
||||||
|
font-family: 'JetBrains Mono', monospace;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #e8eaf0;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
margin: 32px 0 10px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
.prose { max-width: 820px; }
|
||||||
|
.prose p {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #b4bccf;
|
||||||
|
margin-bottom: 14px;
|
||||||
|
line-height: 1.7;
|
||||||
|
}
|
||||||
|
.prose p b { color: #e8eaf0; font-weight: 600; }
|
||||||
|
.prose code {
|
||||||
|
font-family: 'JetBrains Mono', monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #7ab0ff;
|
||||||
|
background: #121829;
|
||||||
|
padding: 1px 5px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
.prose a { color: #0066ff; text-decoration: none; }
|
||||||
|
.prose a:hover { text-decoration: underline; }
|
||||||
|
.prose ul {
|
||||||
|
margin: 8px 0 16px 20px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #b4bccf;
|
||||||
|
line-height: 1.7;
|
||||||
|
}
|
||||||
|
.prose ul li { margin-bottom: 8px; }
|
||||||
|
.cmp-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: 13px;
|
||||||
|
margin: 8px 0 20px;
|
||||||
|
border: 1px solid #1e2a4a;
|
||||||
|
}
|
||||||
|
.cmp-table th {
|
||||||
|
text-align: left;
|
||||||
|
background: #121829;
|
||||||
|
color: #8892a8;
|
||||||
|
font-family: 'JetBrains Mono', monospace;
|
||||||
|
font-size: 11px;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
padding: 10px 14px;
|
||||||
|
border-bottom: 1px solid #1e2a4a;
|
||||||
|
}
|
||||||
|
.cmp-table td {
|
||||||
|
padding: 10px 14px;
|
||||||
|
color: #b4bccf;
|
||||||
|
border-bottom: 1px solid #1e2a4a;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
.cmp-table tr:last-child td { border-bottom: none; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -180,20 +240,64 @@
|
|||||||
<div class="layout">
|
<div class="layout">
|
||||||
|
|
||||||
<nav>
|
<nav>
|
||||||
<a class="active" onclick="show('system')">System</a>
|
<a class="active" onclick="show('walkthrough')">Walkthrough</a>
|
||||||
|
<a onclick="show('system')">System</a>
|
||||||
<a onclick="show('mcp')">MCP Servers</a>
|
<a onclick="show('mcp')">MCP Servers</a>
|
||||||
<a onclick="show('efhas')">FCE Agent</a>
|
<a onclick="show('efhas')">FCE Agent</a>
|
||||||
<a onclick="show('handover')">Handover Agent</a>
|
<a onclick="show('handover')">Handover Agent</a>
|
||||||
<a onclick="show('data')">Data Flow</a>
|
<a onclick="show('data')">Data Flow</a>
|
||||||
<a onclick="show('deploy')">Deployment</a>
|
<a onclick="show('deploy')">Deployment</a>
|
||||||
<a onclick="show('repo')">Repository</a>
|
<a onclick="show('repo')">Repository</a>
|
||||||
|
<a onclick="show('design')">Design</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
|
|
||||||
<section id="system" class="graph-section active">
|
<section id="walkthrough" class="graph-section active">
|
||||||
|
<h2>WALKTHROUGH</h2>
|
||||||
|
<p>A guided tour of the platform — start here for a narrative entry point before diving into the diagrams.</p>
|
||||||
|
<div class="prose">
|
||||||
|
|
||||||
|
<h3>The problem</h3>
|
||||||
|
<p>Stellar Air's operations need two things from the same underlying data. Passenger-facing teams need clear notifications when a flight is disrupted. Ops teams need shift-handover briefs that categorise every open issue by urgency. Both views ride on the same feeds — flights, weather, crew, maintenance — but with different slices, tones, and audiences. This platform unifies them through a shared MCP tool infrastructure.</p>
|
||||||
|
|
||||||
|
<h3>Architecture at a glance</h3>
|
||||||
|
<p>Vue UI → Kong Konnect (optional gateway) → FastAPI → LangGraph agents → MCP clients → three domain-scoped MCP servers → live APIs (OpenMeteo, FAA) and scenario data. The <a onclick="show('system')">System</a> diagram shows the full picture.</p>
|
||||||
|
|
||||||
|
<h3>Data layer</h3>
|
||||||
|
<p>Domain models live in <code>mcp_servers/data/models.py</code> — Pydantic types with enums for flight status, delay causes, and crew roles. Four scenarios (<code>normal_ops</code>, <code>weather_disruption_ord</code>, <code>maintenance_delay_sfo</code>, <code>crew_swap_ewr</code>) are Python modules loaded lazily by <code>mcp_servers/data/scenarios/manager.py</code>; each is a complete, consistent dataset switchable from the UI at runtime. Weather comes live from OpenMeteo (<code>mcp_servers/data/real/openmeteo.py</code>) — real forecasts along calculated route waypoints. Airport status comes live from the FAA NASSTATUS feed (<code>mcp_servers/data/real/faa.py</code>). Neither live source requires an API key.</p>
|
||||||
|
|
||||||
|
<h3>MCP servers</h3>
|
||||||
|
<p>Three servers scoped by access domain. <code>shared</code> exposes the data both agents need — flight status/details, route weather, hub forecasts, airport status/congestion, maintenance flags, and a <code>delay_explainer</code> prompt template. <code>ops</code> adds crew duty, rebookings, a <code>handover-brief</code> prompt, and the handover narrative generator; only the Handover agent connects to it. <code>passenger</code> adds the notification generator and a <code>passenger-notification</code> prompt with selectable tone; only the FCE agent connects to it. Each server declares tools, resources, and prompts.</p>
|
||||||
|
|
||||||
|
<h3>MCP client</h3>
|
||||||
|
<p><code>agents/shared/mcp_client.py</code> defines <code>MCPMultiClient</code> plus a per-agent profile that declares which servers to connect to. Calls are namespaced by server name — <code>mcp.call_tool('shared', 'get_flight_status', …)</code>. Tool results, resource reads, and prompt gets share a common parser and a tool runner that wraps each call in a Langfuse span with timeout and error collection (<code>agents/shared/parser.py</code>, <code>agents/shared/tool_runner.py</code>).</p>
|
||||||
|
|
||||||
|
<h3>Agents</h3>
|
||||||
|
<p>The <b>FCE agent</b> (<code>agents/fce.py</code>) is a four-node LangGraph: triage → gather → synthesize → format. The gather node fires five MCP tool calls in parallel via <code>asyncio.gather</code> — route weather, airport status, airport congestion, flight details, and crew notes — each wrapped in <code>asyncio.wait_for</code> with a 15-second timeout. The synthesis node calls <code>generate_notification</code>; if any gather call failed, the prompt is told which sources are missing and omits them rather than hallucinating.</p>
|
||||||
|
<p>The <b>Handover agent</b> (<code>agents/handover.py</code>) scans every hub in parallel, scores each disruption with a weighted severity × time-sensitivity function (delay minutes, crew duty limits, passenger impact, connection risk), and categorises the results into IMMEDIATE / MONITOR / FYI.</p>
|
||||||
|
|
||||||
|
<h3>API layer</h3>
|
||||||
|
<p>FastAPI (<code>api/main.py</code>) runs agents asynchronously: POST to <code>/agents/fce</code> returns a <code>run_id</code> immediately and the client polls <code>/agents/runs/{run_id}</code>. An <code>EventHub</code> broadcasts lifecycle events over WebSocket — <code>agent_start</code>, <code>node_enter</code>/<code>node_exit</code>, <code>tool_call_end</code>/<code>tool_call_error</code>, <code>agent_end</code> — so the UI can render the agent's internals live. A background task prunes completed runs after one hour. Configuration is centralised in a Pydantic <code>Settings</code> class (<code>api/config.py</code>); HTTP errors surface as proper status codes, not as 200 responses with an error body.</p>
|
||||||
|
|
||||||
|
<h3>Kong Konnect</h3>
|
||||||
|
<p>Kong sits in front as an optional API gateway — rate limiting, request analytics, the path to authentication. The UI reads a gateway URL from local storage or <code>VITE_KONG_PROXY_URL</code>; when empty it falls back to direct FastAPI calls. Kong is additive, not required, so the app keeps working even if the gateway is offline.</p>
|
||||||
|
|
||||||
|
<h3>Frontend</h3>
|
||||||
|
<p>Vue 3 SPA built on the internal <code>soleprint-ui</code> framework. Four tabs: <i>Operations</i> (run agents, see results), <i>Internals</i> (live tool-call stream over WebSocket via <code>useAgentEvents</code>), <i>Data</i> (inspect and edit the active scenario), and <i>Settings</i> (LLM provider, gateway URL). The internals view is the most useful one for understanding what the agent does on each run.</p>
|
||||||
|
|
||||||
|
<h3>Testing</h3>
|
||||||
|
<p>69 tests with dual-mode transport (<code>tests/base.py</code>). Default mode runs against ASGI in-process — fast, no server needed. Set <code>CONTRACT_TEST_MODE=live</code> and <code>CONTRACT_TEST_URL=…</code> to run the same assertions over real HTTP against any deployed instance.</p>
|
||||||
|
|
||||||
|
<h3>Deployment & CI</h3>
|
||||||
|
<p>Woodpecker CI (<code>.woodpecker/build.yml</code>) builds the API and UI images on push to main and pushes them to a private registry. <code>ctrl/deploy.sh</code> has two modes — <code>rsync</code> (copy source, build on the server, for fast iteration) and <code>edge</code> (pull tagged images from the registry, for production). Production runs as docker-compose on EC2 (<code>ctrl/edge/docker-compose.yml</code>) behind nginx, optionally behind Kong. Langfuse runs in a separate Kind cluster and is shared across projects.</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="system" class="graph-section">
|
||||||
<h2>SYSTEM ARCHITECTURE</h2>
|
<h2>SYSTEM ARCHITECTURE</h2>
|
||||||
<p>End-to-end view: Vue UI → Kong gateway → FastAPI → MCP servers → live and scenario data sources. Langfuse traces every agent run.</p>
|
<p>End-to-end view: Vue UI → Kong gateway (optional) → FastAPI → MCP servers → live and scenario data sources. Langfuse (separate shared cluster) traces every agent run and tool call.</p>
|
||||||
<div class="graph-container">
|
<div class="graph-container">
|
||||||
<a href="viewer.html?src=graphs/system_architecture.svg"><img src="graphs/system_architecture.svg" alt="System Architecture"></a>
|
<a href="viewer.html?src=graphs/system_architecture.svg"><img src="graphs/system_architecture.svg" alt="System Architecture"></a>
|
||||||
</div>
|
</div>
|
||||||
@@ -252,7 +356,7 @@
|
|||||||
|
|
||||||
<section id="deploy" class="graph-section">
|
<section id="deploy" class="graph-section">
|
||||||
<h2>DEPLOYMENT</h2>
|
<h2>DEPLOYMENT</h2>
|
||||||
<p>Kind cluster for dev (Tilt), docker-compose for quick start, EC2 for production demo. Entry point: localhost:8040.</p>
|
<p>Kind cluster for dev (Tilt), docker-compose for EC2 production (nova-api + nova-ui on shared gateway network). Woodpecker CI builds images on push to main. EC2 nginx proxies stellarair.mcrn.ar → container; Kong Konnect available as optional governance layer.</p>
|
||||||
<div class="graph-container">
|
<div class="graph-container">
|
||||||
<a href="viewer.html?src=graphs/deployment.svg"><img src="graphs/deployment.svg" alt="Deployment"></a>
|
<a href="viewer.html?src=graphs/deployment.svg"><img src="graphs/deployment.svg" alt="Deployment"></a>
|
||||||
</div>
|
</div>
|
||||||
@@ -260,47 +364,116 @@
|
|||||||
|
|
||||||
<section id="repo" class="graph-section">
|
<section id="repo" class="graph-section">
|
||||||
<h2>REPOSITORY STRUCTURE</h2>
|
<h2>REPOSITORY STRUCTURE</h2>
|
||||||
<p>Monorepo: MCP servers, agents, IRROP engine, API, Vue UI (with shared component framework), and deployment configs.</p>
|
<p>Monorepo: MCP servers, agents, API, Vue UI (with shared component framework), and deployment configs.</p>
|
||||||
<div class="tree-container">
|
<div class="tree-container">
|
||||||
<pre class="repo-tree"><span class="t-root">stellar-ops/</span>
|
<pre class="repo-tree"><span class="t-root">stellar-ops/</span>
|
||||||
├── <span class="t-dir">mcp_servers/</span>
|
├── <span class="t-dir">mcp_servers/</span>
|
||||||
│ ├── <span class="t-mcp">shared/</span> <span class="t-comment">server.py — tools/ resources/ prompts/</span>
|
│ ├── <span class="t-mcp">shared/</span> <span class="t-comment">server.py · tools.py · resources.py · prompts.py</span>
|
||||||
│ │ └── tools: <span class="t-live">get_route_weather</span> · <span class="t-live">get_hub_forecasts</span> · <span class="t-live">get_airport_status</span>
|
│ │ └── tools: <span class="t-live">get_route_weather</span> · <span class="t-live">get_hub_forecasts</span> · <span class="t-live">get_airport_status</span>
|
||||||
│ │ get_flight_status · get_flight_details · get_irregular_ops
|
│ │ get_flight_status · get_flight_details · get_irregular_ops
|
||||||
│ │ get_airport_congestion · get_maintenance_flags
|
│ │ get_airport_congestion · get_maintenance_flags
|
||||||
│ ├── <span class="t-ops">ops/</span> <span class="t-comment">server.py — tools/ resources/ prompts/</span>
|
│ ├── <span class="t-ops">ops/</span> <span class="t-comment">server.py · tools.py · resources.py · prompts.py</span>
|
||||||
│ │ └── tools: get_crew_notes · get_crew_duty_status · get_pending_rebookings
|
│ │ └── tools: get_crew_notes · get_crew_duty_status · get_pending_rebookings
|
||||||
│ │ generate_narrative
|
│ │ generate_narrative
|
||||||
│ ├── <span class="t-pax">passenger/</span> <span class="t-comment">server.py — tools/ resources/ prompts/</span>
|
│ ├── <span class="t-pax">passenger/</span> <span class="t-comment">server.py · tools.py · resources.py · prompts.py</span>
|
||||||
│ │ └── tools: generate_notification
|
│ │ └── tools: generate_notification
|
||||||
|
│ ├── shared_llm.py <span class="t-comment">multi-provider: Groq · Anthropic · Bedrock · OpenAI</span>
|
||||||
│ └── <span class="t-dir">data/</span>
|
│ └── <span class="t-dir">data/</span>
|
||||||
│ ├── models.py <span class="t-comment">FlightData, CrewMember, Passenger, MELItem, HubInfo</span>
|
│ ├── models.py <span class="t-comment">FlightData · CrewMember · Passenger · MELItem · HubInfo</span>
|
||||||
│ ├── real/ <span class="t-live">openmeteo.py · faa.py</span>
|
│ ├── real/ <span class="t-live">openmeteo.py · faa.py</span>
|
||||||
│ └── scenarios/ <span class="t-comment">normal_ops · weather_disruption_ord</span>
|
│ └── scenarios/ <span class="t-comment">normal_ops · weather_disruption_ord</span>
|
||||||
│ <span class="t-comment">maintenance_delay_sfo · crew_swap_ewr</span>
|
│ <span class="t-comment">maintenance_delay_sfo · crew_swap_ewr</span>
|
||||||
├── <span class="t-dir">agents/</span>
|
├── <span class="t-dir">agents/</span>
|
||||||
│ ├── fce.py <span class="t-comment">FCE — "Behind Every Departure"</span>
|
│ ├── fce.py <span class="t-comment">FCE — "Behind Every Departure" (passenger notifications)</span>
|
||||||
│ ├── handover.py <span class="t-comment">Shift Handover agent</span>
|
│ ├── handover.py <span class="t-comment">Shift Handover (ops brief: IMMEDIATE / MONITOR / FYI)</span>
|
||||||
│ └── shared/ <span class="t-comment">mcp_client.py · llm.py (Bedrock/Anthropic)</span>
|
│ └── shared/
|
||||||
├── <span class="t-dir">irrop/</span> <span class="t-comment">Disruption Recovery Engine (Project 3)</span>
|
│ ├── mcp_client.py <span class="t-comment">MCPMultiClient + connect_servers context manager</span>
|
||||||
│ ├── models/ <span class="t-comment">flight · passenger · crew · recovery</span>
|
│ ├── parser.py <span class="t-comment">parse_tool_result · parse_resource_result · parse_prompt_result</span>
|
||||||
│ ├── rules/ <span class="t-comment">faa_part117 · rebooking · compensation</span>
|
│ └── tool_runner.py <span class="t-comment">build_tool_caller — timeout · Langfuse span · error collection</span>
|
||||||
│ └── pipeline/ <span class="t-comment">ingest → triage → rebook → compensate</span>
|
|
||||||
├── <span class="t-dir">api/</span>
|
├── <span class="t-dir">api/</span>
|
||||||
│ └── main.py <span class="t-comment">FastAPI + WebSocket + scenario data API</span>
|
│ ├── main.py <span class="t-comment">FastAPI: agents, scenarios, WebSocket, /health, Langfuse traces</span>
|
||||||
|
│ └── config.py <span class="t-comment">Pydantic Settings — centralized env var reads</span>
|
||||||
├── <span class="t-dir">ui/</span>
|
├── <span class="t-dir">ui/</span>
|
||||||
│ ├── framework/ <span class="t-comment">soleprint-ui (shared component library)</span>
|
│ ├── framework/ <span class="t-comment">soleprint-ui (shared component library)</span>
|
||||||
│ └── app/ <span class="t-comment">Vue 3 SPA — Operations · Internals · Data</span>
|
│ └── app/ <span class="t-comment">Vue 3 SPA — Operations · Internals · Data · Settings</span>
|
||||||
|
│ └── src/config.ts <span class="t-comment">Kong proxy URL + API/WS base</span>
|
||||||
├── <span class="t-dir">ctrl/</span>
|
├── <span class="t-dir">ctrl/</span>
|
||||||
│ ├── Dockerfile.api/ui <span class="t-comment">Container builds</span>
|
│ ├── Dockerfile.api/ui <span class="t-comment">Container builds</span>
|
||||||
|
│ ├── nginx.conf <span class="t-comment">UI nginx (proxies /agents /scenarios /config /health /ws)</span>
|
||||||
│ ├── k8s/ <span class="t-comment">base/ + overlays/dev/ (Kustomize)</span>
|
│ ├── k8s/ <span class="t-comment">base/ + overlays/dev/ (Kustomize)</span>
|
||||||
│ ├── Tiltfile <span class="t-comment">Dev environment (Kind cluster: unt)</span>
|
│ ├── Tiltfile <span class="t-comment">Dev environment (Kind cluster: unt)</span>
|
||||||
│ └── docker-compose.yml <span class="t-comment">Simple alternative</span>
|
│ ├── edge/ <span class="t-comment">Production docker-compose (nova-api + nova-ui on gateway net)</span>
|
||||||
|
│ └── deploy.sh <span class="t-comment">rsync (bypass CI) · edge (pull registry images)</span>
|
||||||
|
├── <span class="t-dir">tests/</span> <span class="t-comment">69 tests: models · clients · MCP · scenarios · agents</span>
|
||||||
|
│ └── base.py <span class="t-comment">dual-mode: inprocess (default) · live (CONTRACT_TEST_MODE=live)</span>
|
||||||
|
├── <span class="t-dir">.woodpecker/</span> <span class="t-comment">CI pipeline — build API + UI, push to registry.mcrn.ar</span>
|
||||||
├── <span class="t-dir">docs/</span> <span class="t-comment">Architecture graphs (this page)</span>
|
├── <span class="t-dir">docs/</span> <span class="t-comment">Architecture graphs (this page)</span>
|
||||||
└── .mcp.json <span class="t-comment">Claude Code integration — 3 servers</span></pre>
|
└── .mcp.json <span class="t-comment">Claude Code integration — 3 servers</span></pre>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section id="design" class="graph-section">
|
||||||
|
<h2>DESIGN NOTES</h2>
|
||||||
|
<p>Rationale behind the non-obvious choices, and a roadmap of deferred improvements. Protocol references link to the MCP spec at <a href="https://modelcontextprotocol.io" target="_blank" rel="noopener">modelcontextprotocol.io</a>.</p>
|
||||||
|
<div class="prose">
|
||||||
|
|
||||||
|
<h3>Concurrency model</h3>
|
||||||
|
<p>Everything runs on one OS thread under asyncio — no GIL contention, no thread locks. Shared mutable state (<code>runs: dict</code>, <code>event_hub._clients: set</code>) is safe because mutations are atomic relative to the event loop scheduler, and disconnects happen between awaits so broadcast iteration is race-free. The FCE agent fires five <code>asyncio.create_task</code> calls then <code>asyncio.gather</code> — five MCP tool calls run concurrently but cooperatively. This only breaks once <code>runs</code> grows large enough to want sharding across processes, at which point the in-process guarantees evaporate and a Redis-backed store becomes necessary (see Roadmap).</p>
|
||||||
|
|
||||||
|
<h3>Stateless API, stateful MCP subprocesses</h3>
|
||||||
|
<p>Each agent run spawns three MCP server subprocesses over stdio. This is wasteful per-request (~500 ms cold-start) but has one decisive advantage: full isolation. No shared scenario state across runs, no mutex on the scenario manager, no "wait, whose data was this?". The path forward is Streamable HTTP transport with long-lived servers — same tool code, different transport — which is a config change rather than a rewrite.</p>
|
||||||
|
|
||||||
|
<h3>Domain-scoped MCP servers</h3>
|
||||||
|
<p>Three servers — <code>shared</code>, <code>ops</code>, <code>passenger</code> — not one with RBAC filtering. The passenger agent literally cannot call <code>get_crew_duty_status</code> because it never connects to the ops server; the capability isn't even discoverable. Security boundary by architecture, not by authorization. Filter bugs become security bugs; MCP is a capability protocol, so using its native scoping is cleaner than bolting auth on top. If ops tools ever move to a separate team or repo they just become a separately-deployed MCP server — agents update their profile, not their code.</p>
|
||||||
|
|
||||||
|
<h3>Tools, Resources, and Prompts</h3>
|
||||||
|
<p>All three MCP primitives are used. <b>Tools</b> are actions or queries with potential side effects: <code>get_flight_status</code>, <code>generate_notification</code>. <b>Resources</b> are read-only data with URIs: <code>ops://hubs/{code}</code>, <code>ops://handover/latest</code> — a dynamic resource (updated after each handover) is still a resource because reading it has no side effects. <b>Prompts</b> are server-versioned templates: <code>delay_explainer(cause_code, audience)</code>, <code>passenger-notification(tone)</code>. The split matters because it lets the server own prompt versioning — update the template on the server and every client picks it up without a redeploy.</p>
|
||||||
|
|
||||||
|
<h3>Why MCP over function calling, LangChain, or direct APIs</h3>
|
||||||
|
<p>MCP wins when there are multiple consumers of the same tools (here, both a LangGraph agent and Claude Code), when dynamic tool discovery matters, and when protocol-level contracts are worth having. Provider function calling (OpenAI, Anthropic) bakes tool definitions into prompts and locks to one vendor. LangChain tools couple to LangChain's abstractions. Direct API calls are the N×M integration problem. MCP doesn't replace function calling — the LLM still uses its native tool-calling mechanism — it standardises the execution layer underneath.</p>
|
||||||
|
<table class="cmp-table">
|
||||||
|
<thead><tr><th>Approach</th><th>Strengths</th><th>Weaknesses</th></tr></thead>
|
||||||
|
<tbody>
|
||||||
|
<tr><td>MCP</td><td>Standard, discoverable, client-agnostic, composable</td><td>Extra process, protocol overhead for simple cases</td></tr>
|
||||||
|
<tr><td>Function calling</td><td>Simple, no extra infrastructure</td><td>Provider-locked, no runtime discovery, definitions duplicated per call</td></tr>
|
||||||
|
<tr><td>LangChain tools</td><td>Tight framework integration</td><td>Coupled to LangChain, not usable outside</td></tr>
|
||||||
|
<tr><td>Direct API calls</td><td>No abstraction overhead</td><td>N×M integration problem, no standardisation</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3>LLM provider abstraction</h3>
|
||||||
|
<p>One <code>generate(system_prompt, user_content)</code> function in <code>mcp_servers/shared_llm.py</code> with four backends: Groq (default, free), Anthropic, Bedrock, and any OpenAI-compatible endpoint. Selection happens at runtime via <code>LLM_PROVIDER</code>. LangChain's provider abstraction is heavier than needed here — string in, string out is enough — and switching providers touches one env var rather than the agent code.</p>
|
||||||
|
<p>Every narrative tool also has a structured template fallback. Response format is identical: <code>{"text": str, "provider": str}</code>. The UI surfaces the provider as a badge, so it's always visible whether a response came from an LLM or the template — honest about what mode the system is in. Tests pass without any API key; the demo works without any API key.</p>
|
||||||
|
|
||||||
|
<h3>Scenarios in memory, not a database</h3>
|
||||||
|
<p>Scenarios are Python modules, versioned with git, loaded lazily by the scenario manager. They are deliberately designed datasets, not user-generated content — git is more valuable than CRUD for them, and switching scenarios is a config change rather than a data migration. The reload-on-subprocess-spawn pattern sidesteps the cache-invalidation problem entirely. This would break once scenarios became per-tenant or grew beyond ~50 MB — then it's a database.</p>
|
||||||
|
|
||||||
|
<h3>Dual-mode tests</h3>
|
||||||
|
<p><code>tests/base.py</code> supports two transports with the same 69 assertions. Default (<code>inprocess</code>) uses <code>httpx.AsyncClient</code> over ASGI — no server needed. <code>live</code> mode runs real HTTP against any <code>CONTRACT_TEST_URL</code>, so the same tests validate a deployed instance. Contract tests are definitionally transport-agnostic; duplicating them into two files would be the bug factory every project eventually regrets.</p>
|
||||||
|
|
||||||
|
<h3>Kong as additive</h3>
|
||||||
|
<p>The app works with or without Kong. When <code>VITE_KONG_PROXY_URL</code> is empty the UI calls FastAPI directly; when set it routes through Kong Konnect for rate limiting, analytics, and the path to auth. Graceful degradation beats a broken demo — especially relevant when the gateway sits on a trial subscription with a finite lifetime.</p>
|
||||||
|
|
||||||
|
<h3>Langfuse in a shared cluster</h3>
|
||||||
|
<p>Langfuse runs in its own Kind cluster separate from the app cluster. The v3 stack needs ClickHouse, Redis, MinIO, and a worker — four extra pods that aren't project-specific. Putting it in a shared cluster means every project points <code>LANGFUSE_HOST</code> at the same instance: one dashboard, one set of keys, one upgrade path. That's how Langfuse belongs in production — shared infra, not per-service.</p>
|
||||||
|
|
||||||
|
<h3>Timeouts, TTL cleanup, error handling</h3>
|
||||||
|
<p>Every MCP tool call is wrapped in <code>asyncio.wait_for</code> with a 15-second timeout — long enough to catch real hangs without false positives from slow-but-alive APIs (OpenMeteo and FAA typically respond in under 2 s). On timeout the span is marked <code>ERROR</code> in Langfuse, the error is added to the run's error list, and the agent continues with partial data. The notification prompt is told which sources are missing and omits them rather than hallucinating.</p>
|
||||||
|
<p>The in-memory run store is pruned by a background task that removes completed or errored runs older than one hour. Errors surface with proper HTTP status codes — <code>HTTPException(404, …)</code> for missing resources, <code>400</code> for invalid requests — rather than <code>200</code> responses with an error body, so clients can distinguish failure without parsing the payload.</p>
|
||||||
|
|
||||||
|
<h3>Roadmap</h3>
|
||||||
|
<p>Items deferred intentionally — the system works without them, and each is a clean extension rather than a rewrite.</p>
|
||||||
|
<ul>
|
||||||
|
<li><b>MCP over Streamable HTTP.</b> Replace subprocess-per-run with long-lived server processes. Becomes worthwhile once cold-start latency matters in aggregate or once MCP needs to serve multiple API replicas.</li>
|
||||||
|
<li><b>Redis-backed run store and event bus.</b> Enables multi-instance WebSocket broadcast and survives API restarts. Necessary as soon as the API scales past a single process.</li>
|
||||||
|
<li><b>Database-backed scenarios.</b> Replace the in-memory modules with a datastore once scenarios need to be per-tenant or grow beyond what fits comfortably in git.</li>
|
||||||
|
<li><b>Circuit breakers on external APIs.</b> Exponential backoff and breakers on FAA and OpenMeteo via <code>tenacity</code>. Worth doing once those APIs have their first real outage.</li>
|
||||||
|
<li><b>Kong Key Auth.</b> Per-consumer access control and per-agent rate limits. Unlocks multi-tenant use and a formal API-key lifecycle.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -310,7 +483,8 @@ function show(id) {
|
|||||||
document.querySelectorAll('.graph-section').forEach(s => s.classList.remove('active'));
|
document.querySelectorAll('.graph-section').forEach(s => s.classList.remove('active'));
|
||||||
document.querySelectorAll('nav a').forEach(a => a.classList.remove('active'));
|
document.querySelectorAll('nav a').forEach(a => a.classList.remove('active'));
|
||||||
document.getElementById(id).classList.add('active');
|
document.getElementById(id).classList.add('active');
|
||||||
event.currentTarget.classList.add('active');
|
var navLink = document.querySelector('nav a[onclick="show(\'' + id + '\')"]');
|
||||||
|
if (navLink) navLink.classList.add('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, watch } from 'vue'
|
import { ref, onMounted, watch, inject, type Ref } from 'vue'
|
||||||
import { Panel } from 'soleprint-ui'
|
import { Panel } from 'soleprint-ui'
|
||||||
import { apiFetch } from '../config'
|
import { apiFetch } from '../config'
|
||||||
|
|
||||||
|
const scenarioVersion = inject<Ref<number>>('scenarioVersion', ref(0))
|
||||||
|
|
||||||
const activeTab = ref<'flights' | 'crew' | 'notes' | 'maintenance' | 'rebookings'>('flights')
|
const activeTab = ref<'flights' | 'crew' | 'notes' | 'maintenance' | 'rebookings'>('flights')
|
||||||
const flights = ref<any[]>([])
|
const flights = ref<any[]>([])
|
||||||
const crew = ref<any[]>([])
|
const crew = ref<any[]>([])
|
||||||
@@ -79,6 +81,7 @@ const statusColors: Record<string, string> = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(loadAll)
|
onMounted(loadAll)
|
||||||
|
watch(() => scenarioVersion.value, loadAll)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
Reference in New Issue
Block a user