fortranspire 0.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. fortranspire-0.1.2/.claude/settings.local.json +62 -0
  2. fortranspire-0.1.2/.env.example +43 -0
  3. fortranspire-0.1.2/.github/workflows/analyze.yml +113 -0
  4. fortranspire-0.1.2/.github/workflows/deploy-azure.yml +78 -0
  5. fortranspire-0.1.2/.github/workflows/draft-paper.yml +35 -0
  6. fortranspire-0.1.2/.github/workflows/jax-translation.yml +54 -0
  7. fortranspire-0.1.2/.gitignore +27 -0
  8. fortranspire-0.1.2/.readthedocs.yaml +24 -0
  9. fortranspire-0.1.2/.zenodo.json +49 -0
  10. fortranspire-0.1.2/AZURE_DEPLOYMENT.md +56 -0
  11. fortranspire-0.1.2/Apptainer.analyze +78 -0
  12. fortranspire-0.1.2/CITATION.cff +64 -0
  13. fortranspire-0.1.2/CODE_OF_CONDUCT.md +60 -0
  14. fortranspire-0.1.2/CONTRIBUTING.md +117 -0
  15. fortranspire-0.1.2/Dockerfile +45 -0
  16. fortranspire-0.1.2/Dockerfile.ci +29 -0
  17. fortranspire-0.1.2/Dockerfile.hpc +31 -0
  18. fortranspire-0.1.2/LICENSE +201 -0
  19. fortranspire-0.1.2/OPTIMIZATION_REVIEW.md +134 -0
  20. fortranspire-0.1.2/PKG-INFO +1410 -0
  21. fortranspire-0.1.2/README.md +1324 -0
  22. fortranspire-0.1.2/RECETTE_SEISMIC.md +71 -0
  23. fortranspire-0.1.2/SECURITY.md +78 -0
  24. fortranspire-0.1.2/TUTORIAL_IDE.md +94 -0
  25. fortranspire-0.1.2/apptainer.def +21 -0
  26. fortranspire-0.1.2/batch_audit.sh +113 -0
  27. fortranspire-0.1.2/bencher_report.json +1 -0
  28. fortranspire-0.1.2/codemeta.json +114 -0
  29. fortranspire-0.1.2/docker-compose.yml +22 -0
  30. fortranspire-0.1.2/docs/api/index.md +20 -0
  31. fortranspire-0.1.2/docs/changelog.md +313 -0
  32. fortranspire-0.1.2/docs/code-of-conduct.md +4 -0
  33. fortranspire-0.1.2/docs/concepts/architecture.md +68 -0
  34. fortranspire-0.1.2/docs/concepts/fortran-patterns.md +26 -0
  35. fortranspire-0.1.2/docs/concepts/le-chat-connector.md +67 -0
  36. fortranspire-0.1.2/docs/concepts/legacy-documentation.md +132 -0
  37. fortranspire-0.1.2/docs/concepts/llm-endpoints.md +53 -0
  38. fortranspire-0.1.2/docs/concepts/mistral-integration.md +186 -0
  39. fortranspire-0.1.2/docs/conf.py +98 -0
  40. fortranspire-0.1.2/docs/contributing.md +4 -0
  41. fortranspire-0.1.2/docs/getting-started/configuration.md +51 -0
  42. fortranspire-0.1.2/docs/getting-started/installation.md +126 -0
  43. fortranspire-0.1.2/docs/getting-started/quickstart.md +92 -0
  44. fortranspire-0.1.2/docs/index.md +65 -0
  45. fortranspire-0.1.2/docs/requirements.txt +6 -0
  46. fortranspire-0.1.2/docs/security.md +4 -0
  47. fortranspire-0.1.2/examples/mistral_agents_api_smoke_test.py +160 -0
  48. fortranspire-0.1.2/fortranspire/__init__.py +14 -0
  49. fortranspire-0.1.2/fortranspire/agent/__init__.py +4 -0
  50. fortranspire-0.1.2/fortranspire/agent/analyze.py +579 -0
  51. fortranspire-0.1.2/fortranspire/agent/batch.py +254 -0
  52. fortranspire-0.1.2/fortranspire/agent/bench.py +368 -0
  53. fortranspire-0.1.2/fortranspire/agent/call_graph.py +306 -0
  54. fortranspire-0.1.2/fortranspire/agent/cli.py +300 -0
  55. fortranspire-0.1.2/fortranspire/agent/code_agent.py +69 -0
  56. fortranspire-0.1.2/fortranspire/agent/diff.py +308 -0
  57. fortranspire-0.1.2/fortranspire/agent/document.py +608 -0
  58. fortranspire-0.1.2/fortranspire/agent/explain.py +391 -0
  59. fortranspire-0.1.2/fortranspire/agent/format.py +136 -0
  60. fortranspire-0.1.2/fortranspire/agent/fortls_oracle.py +112 -0
  61. fortranspire-0.1.2/fortranspire/agent/nodes/__init__.py +38 -0
  62. fortranspire-0.1.2/fortranspire/agent/nodes/_common.py +79 -0
  63. fortranspire-0.1.2/fortranspire/agent/nodes/_state.py +54 -0
  64. fortranspire-0.1.2/fortranspire/agent/nodes/cython_wrapper.py +152 -0
  65. fortranspire-0.1.2/fortranspire/agent/nodes/equivalence_harness.py +231 -0
  66. fortranspire-0.1.2/fortranspire/agent/nodes/extractor.py +238 -0
  67. fortranspire-0.1.2/fortranspire/agent/nodes/init.py +29 -0
  68. fortranspire-0.1.2/fortranspire/agent/nodes/openacc.py +182 -0
  69. fortranspire-0.1.2/fortranspire/agent/nodes/parser.py +270 -0
  70. fortranspire-0.1.2/fortranspire/agent/nodes/pure_elemental.py +84 -0
  71. fortranspire-0.1.2/fortranspire/agent/nodes/validation.py +409 -0
  72. fortranspire-0.1.2/fortranspire/agent/report.py +227 -0
  73. fortranspire-0.1.2/fortranspire/agent/schemas.py +107 -0
  74. fortranspire-0.1.2/fortranspire/agent/toolchain.py +169 -0
  75. fortranspire-0.1.2/fortranspire/agent/translation_graph.py +1601 -0
  76. fortranspire-0.1.2/fortranspire/agent/translation_graph_phase1.py +81 -0
  77. fortranspire-0.1.2/fortranspire/brain/a7b8afb7-b6df-4d7c-9252-618f5c7ff174/scratch/inspect_loki.py +37 -0
  78. fortranspire-0.1.2/fortranspire/brain/a7b8afb7-b6df-4d7c-9252-618f5c7ff174/scratch/test_loki.py +39 -0
  79. fortranspire-0.1.2/fortranspire/cache/__init__.py +31 -0
  80. fortranspire-0.1.2/fortranspire/cache/install.py +92 -0
  81. fortranspire-0.1.2/fortranspire/cache/lru.py +188 -0
  82. fortranspire-0.1.2/fortranspire/cli.py +129 -0
  83. fortranspire-0.1.2/fortranspire/config.py +31 -0
  84. fortranspire-0.1.2/fortranspire/llm/__init__.py +154 -0
  85. fortranspire-0.1.2/fortranspire/main.py +62 -0
  86. fortranspire-0.1.2/fortranspire/observability/__init__.py +27 -0
  87. fortranspire-0.1.2/fortranspire/observability/llm_callback.py +51 -0
  88. fortranspire-0.1.2/fortranspire/observability/pricing.py +70 -0
  89. fortranspire-0.1.2/fortranspire/observability/tracer.py +158 -0
  90. fortranspire-0.1.2/fortranspire/prompts/__init__.py +31 -0
  91. fortranspire-0.1.2/fortranspire/prompts/cython_header/en/v1.md +1 -0
  92. fortranspire-0.1.2/fortranspire/prompts/cython_header/en/v2.md +1 -0
  93. fortranspire-0.1.2/fortranspire/prompts/cython_header/fr/v1.md +1 -0
  94. fortranspire-0.1.2/fortranspire/prompts/cython_header/fr/v2.md +10 -0
  95. fortranspire-0.1.2/fortranspire/prompts/cython_pyx/en/v1.md +1 -0
  96. fortranspire-0.1.2/fortranspire/prompts/cython_pyx/en/v2.md +1 -0
  97. fortranspire-0.1.2/fortranspire/prompts/cython_pyx/fr/v1.md +1 -0
  98. fortranspire-0.1.2/fortranspire/prompts/cython_pyx/fr/v2.md +11 -0
  99. fortranspire-0.1.2/fortranspire/prompts/doc_routine/en/v1.md +5 -0
  100. fortranspire-0.1.2/fortranspire/prompts/doc_routine/fr/v1.md +6 -0
  101. fortranspire-0.1.2/fortranspire/prompts/extractor/en/v1.md +53 -0
  102. fortranspire-0.1.2/fortranspire/prompts/extractor/en/v2.md +53 -0
  103. fortranspire-0.1.2/fortranspire/prompts/extractor/fr/v1.md +53 -0
  104. fortranspire-0.1.2/fortranspire/prompts/extractor/fr/v2.md +61 -0
  105. fortranspire-0.1.2/fortranspire/prompts/loader.py +120 -0
  106. fortranspire-0.1.2/fortranspire/prompts/openacc_driver/en/v1.md +12 -0
  107. fortranspire-0.1.2/fortranspire/prompts/openacc_driver/en/v2.md +12 -0
  108. fortranspire-0.1.2/fortranspire/prompts/openacc_driver/fr/v1.md +13 -0
  109. fortranspire-0.1.2/fortranspire/prompts/openacc_driver/fr/v2.md +21 -0
  110. fortranspire-0.1.2/fortranspire/prompts/openacc_kernel/en/v1.md +19 -0
  111. fortranspire-0.1.2/fortranspire/prompts/openacc_kernel/en/v2.md +19 -0
  112. fortranspire-0.1.2/fortranspire/prompts/openacc_kernel/fr/v1.md +22 -0
  113. fortranspire-0.1.2/fortranspire/prompts/openacc_kernel/fr/v2.md +30 -0
  114. fortranspire-0.1.2/fortranspire/prompts/openmp_driver/en/v2.md +27 -0
  115. fortranspire-0.1.2/fortranspire/prompts/openmp_driver/fr/v2.md +27 -0
  116. fortranspire-0.1.2/fortranspire/prompts/openmp_kernel/en/v2.md +34 -0
  117. fortranspire-0.1.2/fortranspire/prompts/openmp_kernel/fr/v2.md +35 -0
  118. fortranspire-0.1.2/fortranspire/requirements.txt +22 -0
  119. fortranspire-0.1.2/fortranspire/security/__init__.py +36 -0
  120. fortranspire-0.1.2/fortranspire/security/audit.py +107 -0
  121. fortranspire-0.1.2/fortranspire/security/auth.py +216 -0
  122. fortranspire-0.1.2/fortranspire/server.py +188 -0
  123. fortranspire-0.1.2/fortranspire/tools/__init__.py +8 -0
  124. fortranspire-0.1.2/fortranspire/tools/file_tools.py +59 -0
  125. fortranspire-0.1.2/fortranspire/tools/search_tools.py +38 -0
  126. fortranspire-0.1.2/fortranspire/tools/shell_tools.py +36 -0
  127. fortranspire-0.1.2/infrastructure/deploy.sh +66 -0
  128. fortranspire-0.1.2/infrastructure/main.tf +114 -0
  129. fortranspire-0.1.2/infrastructure/variables.tf +4 -0
  130. fortranspire-0.1.2/integration/le-chat-connector.json +106 -0
  131. fortranspire-0.1.2/paper.bib +105 -0
  132. fortranspire-0.1.2/paper.md +131 -0
  133. fortranspire-0.1.2/pyproject.toml +171 -0
  134. fortranspire-0.1.2/scripts/bench_gpu.sh +182 -0
  135. fortranspire-0.1.2/scripts/get_gpu_ip.sh +31 -0
  136. fortranspire-0.1.2/scripts/test_gpu.sh +139 -0
  137. fortranspire-0.1.2/tests/__init__.py +0 -0
  138. fortranspire-0.1.2/tests/cache/__init__.py +0 -0
  139. fortranspire-0.1.2/tests/cache/test_install.py +76 -0
  140. fortranspire-0.1.2/tests/cache/test_lru_cache.py +199 -0
  141. fortranspire-0.1.2/tests/fixtures/doc_kernel.f90 +38 -0
  142. fortranspire-0.1.2/tests/observability/__init__.py +0 -0
  143. fortranspire-0.1.2/tests/observability/test_llm_callback.py +56 -0
  144. fortranspire-0.1.2/tests/observability/test_tracer.py +145 -0
  145. fortranspire-0.1.2/tests/prompts/test_fr_i18n.py +81 -0
  146. fortranspire-0.1.2/tests/prompts/test_loader.py +88 -0
  147. fortranspire-0.1.2/tests/security/__init__.py +0 -0
  148. fortranspire-0.1.2/tests/security/test_audit.py +98 -0
  149. fortranspire-0.1.2/tests/security/test_auth.py +111 -0
  150. fortranspire-0.1.2/tests/security/test_middleware.py +106 -0
  151. fortranspire-0.1.2/tests/test_batch.py +260 -0
  152. fortranspire-0.1.2/tests/test_bench.py +215 -0
  153. fortranspire-0.1.2/tests/test_call_graph.py +155 -0
  154. fortranspire-0.1.2/tests/test_diff.py +157 -0
  155. fortranspire-0.1.2/tests/test_document.py +143 -0
  156. fortranspire-0.1.2/tests/test_equivalence_harness.py +126 -0
  157. fortranspire-0.1.2/tests/test_explain.py +116 -0
  158. fortranspire-0.1.2/tests/test_llm_backend.py +121 -0
  159. fortranspire-0.1.2/tests/test_openmp_target.py +217 -0
  160. fortranspire-0.1.2/tests/test_report.py +133 -0
  161. fortranspire-0.1.2/tests/test_schemas.py +76 -0
  162. fortranspire-0.1.2/tests/test_unified_cli.py +145 -0
  163. fortranspire-0.1.2/uv.lock +4771 -0
@@ -0,0 +1,62 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(git add *)",
5
+ "Bash(git commit -m ' *)",
6
+ "Bash(git push *)",
7
+ "WebSearch",
8
+ "WebFetch(domain:mistral.ai)",
9
+ "WebFetch(domain:www.scaleway.com)",
10
+ "Bash(uv sync *)",
11
+ "Bash(curl -sL https://pypi.org/pypi/loki-frontend/json)",
12
+ "Bash(curl -sL https://pypi.org/pypi/loki/json)",
13
+ "Bash(curl -sL https://api.github.com/repos/ecmwf-ifs/loki/releases/latest)",
14
+ "Bash(python3 -c \"import sys, json; d=json.load\\(sys.stdin\\); print\\('tag:', d.get\\('tag_name'\\), 'name:', d.get\\('name'\\)\\)\")",
15
+ "Bash(curl -sL https://api.github.com/repos/ecmwf-ifs/loki/tags)",
16
+ "Bash(python3 -c \"import sys, json; tags=json.load\\(sys.stdin\\); print\\([t['name'] for t in tags[:10]]\\)\")",
17
+ "Bash(git ls-remote *)",
18
+ "Bash(uv run *)",
19
+ "Bash(.venv/bin/python *)",
20
+ "Bash(pip show *)",
21
+ "Bash(git rm *)",
22
+ "Bash(git checkout *)",
23
+ "Bash(git remote *)",
24
+ "Bash(gh pr create --title 'rename to fortranspire + JOSS scaffolding + agent-analyze / agent-doc / agent-format' --base main --head feature/fortranspire-rename-and-joss --body ' *)",
25
+ "Bash(git pull *)",
26
+ "Bash(awk 'NR==489,NR==733' fortranspire/agent/translation_graph_phase1.py)",
27
+ "Bash(awk 'NR==736,NR==807' fortranspire/agent/translation_graph_phase1.py)",
28
+ "Bash(awk 'NR==810,NR==967' fortranspire/agent/translation_graph_phase1.py)",
29
+ "Bash(awk 'NR==970,NR==1090' fortranspire/agent/translation_graph_phase1.py)",
30
+ "Bash(awk 'NR==1095,NR==1196' fortranspire/agent/translation_graph_phase1.py)",
31
+ "Bash(awk 'NR==1200,NR==1395' fortranspire/agent/translation_graph_phase1.py)",
32
+ "Bash(awk 'NR==1396,NR==1424' fortranspire/agent/translation_graph_phase1.py)",
33
+ "Bash(awk 'NR>=1085 && NR<=1095' fortranspire/agent/translation_graph_phase1.py.bak)",
34
+ "Bash(awk 'NR>=1085 && NR<=1095')",
35
+ "Bash(gh pr create --title '[#2] split monolithic LangGraph file into per-node modules' --base main --head refactor/issue-2-split-graph-nodes --body ' *)",
36
+ "Bash(gh pr create --title '[#3] externalize LLM prompts \\(versioning + i18n\\)' --base main --head refactor/issue-3-externalize-prompts --body ' *)",
37
+ "Bash(gh pr create --title '[#4] Pydantic schemas + documenter structured output' --base main --head refactor/issue-4-structured-outputs --body ' *)",
38
+ "Bash(gh pr *)",
39
+ "Bash(git fetch *)",
40
+ "Bash(git rebase *)",
41
+ "WebFetch(domain:meteofrance.com)",
42
+ "WebFetch(domain:www.bayfor.org)",
43
+ "WebFetch(domain:www.eurohpc-ju.europa.eu)",
44
+ "WebFetch(domain:topictree.ideal-ist.eu)",
45
+ "WebFetch(domain:www.marches-publics.gouv.fr)",
46
+ "WebFetch(domain:www.ecmwf.int)",
47
+ "WebFetch(domain:www.marchesonline.com)",
48
+ "WebFetch(domain:hpc-portal.eu)",
49
+ "Bash(uv build *)",
50
+ "Bash(git tag -a v0.1.0 -m ' *)",
51
+ "Bash(git tag *)",
52
+ "Bash(gh release *)",
53
+ "Bash(gh api *)",
54
+ "Bash(curl -sI https://github.com/maurinl26/loki)",
55
+ "Bash(curl -sI https://pypi.org/project/loki/)",
56
+ "Bash(curl -sI https://pypi.org/project/loki-fortranspire/)",
57
+ "Bash(curl -sI https://pypi.org/project/ecmwf-loki/)",
58
+ "Bash(curl -sI https://pypi.org/project/loki-ifs/)",
59
+ "Bash(curl -s -o /dev/null -w '%{http_code}' https://pypi.org/pypi/__TRACKED_VAR__/json)"
60
+ ]
61
+ }
62
+ }
@@ -0,0 +1,43 @@
1
+ # Copier ce fichier en .env et adapter les valeurs
2
+
3
+ # ----------------------------------------------------
4
+ # Endpoint Mistral (OpenAI-compatible)
5
+ # ----------------------------------------------------
6
+ # Par défaut : La Plateforme Mistral (hébergement souverain en Europe).
7
+ # Alternatives : vLLM / TGI / Ollama auto-hébergés on-prem ou cloud privé.
8
+ MISTRAL_ENDPOINT="https://api.mistral.ai/v1"
9
+ MISTRAL_API_KEY="votre_clef_mistral_ici_xxxxxx"
10
+
11
+ # ── Modèle par étape du pipeline ────────────────────────────────────────────
12
+ # Le pipeline a deux types d'appels LLM :
13
+ # - reasoning (extractor, openacc) → besoin d'un gros modèle de raisonnement
14
+ # - code (cython_wrapper) → Codestral suffit, moins cher, plus rapide
15
+ #
16
+ # Si une variable spécifique est définie, elle prime. Sinon, fallback sur
17
+ # MISTRAL_MODEL (legacy, un seul modèle pour tout), puis sur les défauts.
18
+ MISTRAL_MODEL_REASONING="mistral-large-latest"
19
+ MISTRAL_MODEL_CODE="codestral-latest"
20
+
21
+ # Legacy : un seul modèle pour les deux étapes. Décommenter pour forcer.
22
+ # MISTRAL_MODEL="mistral-large-latest"
23
+
24
+ # Note : aucune variable AZURE_* n'est lue. L'agent appelle l'endpoint
25
+ # OpenAI-compatible défini ci-dessus directement, sans intermédiaire.
26
+
27
+
28
+ # Paramètres de génération
29
+ LLM_TEMPERATURE=0.0
30
+ LLM_TOP_P=0.9
31
+ LLM_NUM_PREDICT=2048
32
+
33
+ # Agent
34
+ AGENT_MAX_ITERATIONS=15
35
+ AGENT_MEMORY_WINDOW=10
36
+
37
+ # Authentification (Optionnelle)
38
+ # Laissez vide pour un accès public.
39
+ # Renseignez une valeur pour forcer le header 'Authorization: Bearer <API_KEY>'
40
+ # API_KEY=ma_clef_secrete_123
41
+
42
+ # Répertoire de travail (laisser vide = racine du projet)
43
+ # AGENT_WORKSPACE=/path/to/your/project
@@ -0,0 +1,113 @@
1
+ name: Fortran static analysis
2
+
3
+ # Runs the deterministic Loki-based parser on every PR and push.
4
+ # No LLM is called, no token is consumed — safe on forks.
5
+ # Findings are uploaded as SARIF and surface as inline PR annotations
6
+ # via GitHub Code Scanning.
7
+
8
+ on:
9
+ pull_request:
10
+ paths:
11
+ - '**/*.f90'
12
+ - '**/*.F90'
13
+ - 'local_code_agent/**'
14
+ - '.github/workflows/analyze.yml'
15
+ push:
16
+ branches: [main]
17
+ paths:
18
+ - '**/*.f90'
19
+ - '**/*.F90'
20
+ - 'local_code_agent/**'
21
+ - '.github/workflows/analyze.yml'
22
+ workflow_dispatch:
23
+ inputs:
24
+ target_path:
25
+ description: 'Path to analyze (file or directory)'
26
+ required: false
27
+ default: '.'
28
+
29
+ permissions:
30
+ contents: read
31
+ security-events: write # required to upload SARIF
32
+ pull-requests: read
33
+
34
+ jobs:
35
+ analyze:
36
+ name: agent-analyze (Loki, no LLM)
37
+ runs-on: ubuntu-latest
38
+ timeout-minutes: 10
39
+
40
+ steps:
41
+ - name: Checkout
42
+ uses: actions/checkout@v4
43
+ with:
44
+ fetch-depth: 2 # need HEAD~1 to diff changed files on PR
45
+
46
+ - name: Install uv
47
+ uses: astral-sh/setup-uv@v3
48
+ with:
49
+ enable-cache: true
50
+
51
+ - name: Set up Python 3.12
52
+ run: uv python install 3.12
53
+
54
+ - name: Install project (no LLM extras needed)
55
+ run: uv sync --no-dev
56
+
57
+ - name: Pick paths to analyze
58
+ id: paths
59
+ run: |
60
+ set -euo pipefail
61
+ if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
62
+ echo "targets=${{ github.event.inputs.target_path }}" >> "$GITHUB_OUTPUT"
63
+ exit 0
64
+ fi
65
+ if [ "${{ github.event_name }}" = "pull_request" ]; then
66
+ git fetch --no-tags --depth=1 origin "${{ github.base_ref }}"
67
+ changed=$(git diff --name-only --diff-filter=ACMR \
68
+ "origin/${{ github.base_ref }}...HEAD" \
69
+ | grep -E '\.(f90|F90)$' || true)
70
+ else
71
+ changed=$(git diff --name-only --diff-filter=ACMR HEAD~1 HEAD \
72
+ | grep -E '\.(f90|F90)$' || true)
73
+ fi
74
+ if [ -z "$changed" ]; then
75
+ echo "No Fortran files changed — analyzer will scan the whole repo."
76
+ echo "targets=." >> "$GITHUB_OUTPUT"
77
+ else
78
+ echo "Changed Fortran files:"
79
+ echo "$changed"
80
+ echo "targets<<EOF" >> "$GITHUB_OUTPUT"
81
+ echo "$changed" >> "$GITHUB_OUTPUT"
82
+ echo "EOF" >> "$GITHUB_OUTPUT"
83
+ fi
84
+
85
+ - name: Run analyzer (text — console)
86
+ continue-on-error: true
87
+ run: |
88
+ # shellcheck disable=SC2086
89
+ uv run agent-analyze --no-color ${{ steps.paths.outputs.targets }}
90
+
91
+ - name: Run analyzer (SARIF — for Code Scanning)
92
+ run: |
93
+ # shellcheck disable=SC2086
94
+ uv run agent-analyze \
95
+ --format sarif \
96
+ --fail-on error \
97
+ --output fortranspire.sarif \
98
+ ${{ steps.paths.outputs.targets }}
99
+
100
+ - name: Upload SARIF to GitHub Code Scanning
101
+ if: always()
102
+ uses: github/codeql-action/upload-sarif@v3
103
+ with:
104
+ sarif_file: fortranspire.sarif
105
+ category: fortranspire
106
+
107
+ - name: Upload SARIF as build artifact
108
+ if: always()
109
+ uses: actions/upload-artifact@v4
110
+ with:
111
+ name: fortranspire-sarif
112
+ path: fortranspire.sarif
113
+ if-no-files-found: warn
@@ -0,0 +1,78 @@
1
+ name: 'Azure Infrastructure Control'
2
+
3
+ on:
4
+ # Permet le lancement manuel depuis l'onglet "Actions" de GitHub
5
+ workflow_dispatch:
6
+ inputs:
7
+ action:
8
+ description: 'Action à effectuer (apply / destroy)'
9
+ required: true
10
+ default: 'apply'
11
+ type: choice
12
+ options:
13
+ - apply
14
+ - destroy
15
+
16
+ permissions:
17
+ contents: read
18
+
19
+ jobs:
20
+ terraform:
21
+ name: 'Terraform ${{ github.event.inputs.action }}'
22
+ runs-on: ubuntu-latest
23
+ env:
24
+ ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
25
+ ARM_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
26
+ ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
27
+ ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
28
+ TF_VAR_ssh_public_key: ${{ secrets.DEPLOY_SSH_PUBKEY }}
29
+
30
+ steps:
31
+ - name: Checkout Code
32
+ uses: actions/checkout@v4
33
+
34
+ - name: Setup Terraform
35
+ uses: hashicorp/setup-terraform@v3
36
+
37
+ - name: Terraform Init
38
+ run: terraform init
39
+ working-directory: infrastructure
40
+
41
+ - name: Azure CLI Login
42
+ run: az login --service-principal -u $ARM_CLIENT_ID -p $ARM_CLIENT_SECRET --tenant $ARM_TENANT_ID
43
+
44
+ - name: Cleanup Stale Resources
45
+ if: github.event.inputs.action == 'apply'
46
+ run: |
47
+ # If RG exists in wrong region, delete it entirely — location is immutable so Terraform
48
+ # would try destroy+recreate anyway, but the orphaned NIC-ORCHESTRATOR blocks VNet deletion.
49
+ LOCATION=$(az group show --name rg-total-seismic-agent --query location -o tsv 2>/dev/null || echo "")
50
+ if [ -n "$LOCATION" ] && [ "$LOCATION" != "eastus" ]; then
51
+ echo "RG is in '$LOCATION', deleting so Terraform can recreate in eastus..."
52
+ az group delete --name rg-total-seismic-agent --yes
53
+ fi
54
+
55
+ - name: Import Pre-existing Resources
56
+ if: github.event.inputs.action == 'apply'
57
+ working-directory: infrastructure
58
+ run: |
59
+ SUB="/subscriptions/${ARM_SUBSCRIPTION_ID}"
60
+ RG="rg-total-seismic-agent"
61
+ terraform import azurerm_resource_group.rg \
62
+ "${SUB}/resourceGroups/${RG}" 2>/dev/null || true
63
+ terraform import azurerm_virtual_network.vnet \
64
+ "${SUB}/resourceGroups/${RG}/providers/Microsoft.Network/virtualNetworks/vnet-seismic" 2>/dev/null || true
65
+ terraform import azurerm_subnet.subnet_compute \
66
+ "${SUB}/resourceGroups/${RG}/providers/Microsoft.Network/virtualNetworks/vnet-seismic/subnets/snet-compute" 2>/dev/null || true
67
+ terraform import azurerm_network_interface.nic_gpu \
68
+ "${SUB}/resourceGroups/${RG}/providers/Microsoft.Network/networkInterfaces/nic-gpu" 2>/dev/null || true
69
+ terraform import azurerm_ai_services.ai_studio \
70
+ "${SUB}/resourceGroups/${RG}/providers/Microsoft.CognitiveServices/accounts/ai-hub-seismic" 2>/dev/null || true
71
+
72
+ - name: Terraform Plan
73
+ run: terraform plan -input=false ${{ github.event.inputs.action == 'destroy' && '-destroy' || '' }}
74
+ working-directory: infrastructure
75
+
76
+ - name: Terraform Action
77
+ run: terraform ${{ github.event.inputs.action }} -auto-approve -input=false
78
+ working-directory: infrastructure
@@ -0,0 +1,35 @@
1
+ name: JOSS paper draft
2
+
3
+ on:
4
+ push:
5
+ paths:
6
+ - paper.md
7
+ - paper.bib
8
+ - .github/workflows/draft-paper.yml
9
+ pull_request:
10
+ paths:
11
+ - paper.md
12
+ - paper.bib
13
+ - .github/workflows/draft-paper.yml
14
+ workflow_dispatch:
15
+
16
+ jobs:
17
+ paper:
18
+ runs-on: ubuntu-latest
19
+ name: Render paper.md via Open Journals Docker action
20
+ steps:
21
+ - name: Checkout
22
+ uses: actions/checkout@v4
23
+
24
+ - name: Build draft PDF
25
+ uses: openjournals/openjournals-draft-action@master
26
+ with:
27
+ journal: joss
28
+ paper-path: paper.md
29
+
30
+ - name: Upload rendered PDF as artifact
31
+ uses: actions/upload-artifact@v4
32
+ with:
33
+ name: paper
34
+ path: paper.pdf
35
+ if-no-files-found: error
@@ -0,0 +1,54 @@
1
+ name: Fortran to JAX Automated Translation
2
+
3
+ on:
4
+ pull_request:
5
+ paths:
6
+ - '**/*.f90'
7
+ - '**/*.F90'
8
+ - '**/*.f'
9
+ workflow_dispatch:
10
+
11
+ jobs:
12
+ translation-and-profiling:
13
+ runs-on: ubuntu-latest
14
+ container:
15
+ image: ghcr.io/${{ github.repository_owner }}/jax-translation-agent:latest
16
+ steps:
17
+ - name: Checkout Code
18
+ uses: actions/checkout@v4
19
+ with:
20
+ fetch-depth: 0
21
+
22
+ - name: Install Bencher
23
+ uses: bencherdev/bencher@main
24
+
25
+ - name: Run Multi-Agent Translator and Bencher
26
+ env:
27
+ BENCHER_PROJECT: seismic-cpml
28
+ BENCHER_TESTBED: ubuntu-latest
29
+ BENCHER_ADAPTER: json
30
+ run: |
31
+ # Finds all specifically added/modified .f90 files in this PR
32
+ CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }} HEAD | grep -E '\.f90$|\.F90$')
33
+
34
+ for file in $CHANGED_FILES; do
35
+ echo "Processing $file..."
36
+
37
+ # Exécution du pipeine englobé par Bencher
38
+ bencher run \
39
+ --project "seismic-cpml" \
40
+ --token "${{ secrets.BENCHER_API_TOKEN }}" \
41
+ --branch "${{ github.ref_name }}" \
42
+ --adapter json \
43
+ --file bencher_report.json \
44
+ --err \
45
+ "python -m local_code_agent.agent.cli translate \"$file\" && python -m local_code_agent.agent.cli profile \"$file\""
46
+ done
47
+
48
+ - name: Commit and Push Translated JAX Code
49
+ run: |
50
+ git config --global user.name "github-actions[bot]"
51
+ git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
52
+ git add "**/*_jax.py"
53
+ git commit -m "chore: Auto-translated Fortran to JAX :robot:" || echo "No changes to commit"
54
+ git push
@@ -0,0 +1,27 @@
1
+ .env
2
+ .DS_Store
3
+ **/*.node
4
+ .venv/
5
+
6
+ # Node/Web
7
+ node_modules/
8
+ .next/
9
+ dist/
10
+ build/
11
+
12
+ # Python cache
13
+ __pycache__/
14
+ *.pyc
15
+
16
+ # HPC / Big data
17
+ *.sif
18
+ *.tar.gz
19
+ *.h5
20
+ *.nc
21
+ *.o
22
+ *.mod
23
+ *.so
24
+
25
+ #
26
+ output/
27
+ loki/
@@ -0,0 +1,24 @@
1
+ # Read the Docs configuration — see https://docs.readthedocs.io/en/stable/config-file/v2.html
2
+ version: 2
3
+
4
+ build:
5
+ os: ubuntu-24.04
6
+ tools:
7
+ python: "3.12"
8
+ jobs:
9
+ post_create_environment:
10
+ - pip install --upgrade pip
11
+
12
+ python:
13
+ install:
14
+ - requirements: docs/requirements.txt
15
+ - method: pip
16
+ path: .
17
+
18
+ sphinx:
19
+ configuration: docs/conf.py
20
+ fail_on_warning: false
21
+
22
+ formats:
23
+ - pdf
24
+ - epub
@@ -0,0 +1,49 @@
1
+ {
2
+ "title": "fortranspire: LLM + MCP pipeline porting legacy Fortran HPC kernels to OpenACC GPU and differentiable JAX",
3
+ "description": "<p><strong>fortranspire</strong> is an open-source Model Context Protocol (MCP) server and CLI that incrementally transforms legacy Fortran 90 scientific code into GPU-accelerated (OpenACC), Python-callable (Cython / scikit-build), and optionally differentiable (JAX) form. It combines deterministic Loki AST analysis with targeted LLM calls against any OpenAI-compatible endpoint (Mistral, vLLM, TGI, Ollama).</p>",
4
+ "license": "Apache-2.0",
5
+ "upload_type": "software",
6
+ "access_right": "open",
7
+ "creators": [
8
+ {
9
+ "name": "Maurin, Loïc",
10
+ "affiliation": "External Lecturer, École Nationale de la Météorologie, Toulouse, France",
11
+ "orcid": "0009-0004-8117-4850"
12
+ }
13
+ ],
14
+ "keywords": [
15
+ "Fortran",
16
+ "HPC",
17
+ "GPU",
18
+ "OpenACC",
19
+ "JAX",
20
+ "Cython",
21
+ "scikit-build",
22
+ "Loki",
23
+ "ECMWF",
24
+ "Model Context Protocol",
25
+ "MCP",
26
+ "large language models",
27
+ "Mistral",
28
+ "scientific computing",
29
+ "seismic imaging",
30
+ "numerical weather prediction",
31
+ "neural surrogates",
32
+ "code generation",
33
+ "agent",
34
+ "sovereign AI"
35
+ ],
36
+ "communities": [
37
+ {
38
+ "identifier": "joss"
39
+ }
40
+ ],
41
+ "related_identifiers": [
42
+ {
43
+ "identifier": "https://github.com/maurinl26/fortranspire",
44
+ "relation": "isSupplementTo",
45
+ "scheme": "url"
46
+ }
47
+ ],
48
+ "language": "eng"
49
+ }
@@ -0,0 +1,56 @@
1
+ # Guide de Déploiement : Azure pour TotalEnergies
2
+
3
+ Ce document détaille l'architecture et les prérequis pour déployer l'Agent LangGraph de traduction Fortran ➔ JAX dans un environnement sécurisé Microsoft Azure (orienté Enterprise).
4
+
5
+ ## 1. Architecture Cible
6
+
7
+ Pour ce cas d'usage traitant de physiques lourdes (EDP, C-PML) et d'intelligence artificielle générative, l'architecture se divise en trois composants :
8
+
9
+ 1. **Serveur Orchestrateur (Compute)** : Exécute le code LangGraph (`translation_graph.py`), parse les arbres de syntaxe avec `loki-ifs` et héberge l'interface FastMCP.
10
+ - *Instance recommandée :* `Standard_D8s_v5` (Machine optimisée calcul à usage général).
11
+ 2. **Nœud d'inférence Physique / JAX (GPU)** : Exécute la simulation JAX compilée (JIT) et entraîne le surrogate model de type Fourier Neural Operator (FNO).
12
+ - *Instance recommandée :* `Standard_NCads_A100_v4` (qui dispose d'un GPU Nvidia A100 80GB) pour supporter de grandes dimensions spatiales.
13
+ 3. **Le Cerveau IA (Le LLM Mistral)** : Assure la compréhension mathématique et la traduction.
14
+ - *Service par défaut :* **La Plateforme Mistral** (`api.mistral.ai`) — endpoint souverain opéré en Europe par Mistral AI, sans intermédiaire hyperscaler.
15
+ - *Alternative on-prem :* vLLM/TGI hébergé sur la VM GPU ci-dessus, exposant la même API OpenAI-compatible.
16
+
17
+ ---
18
+
19
+ ## 2. Accès à Mistral : endpoint souverain
20
+
21
+ L'agent n'utilise pas Azure AI Studio pour le LLM. La connexion se fait **directement** vers un endpoint Mistral OpenAI-compatible :
22
+
23
+ 1. Créer une clef sur [console.mistral.ai](https://console.mistral.ai/) → *API Keys*.
24
+ 2. Renseigner `.env` :
25
+
26
+ ```env
27
+ MISTRAL_ENDPOINT="https://api.mistral.ai/v1"
28
+ MISTRAL_API_KEY="<clef_mistral>"
29
+ MISTRAL_MODEL="mistral-large-latest"
30
+ ```
31
+
32
+ Pour une souveraineté complète (données + poids du modèle hors cloud public), pointer `MISTRAL_ENDPOINT` vers un serveur vLLM/TGI auto-hébergé sur la VM GPU listée au §1. Voir la section "Connecter un endpoint Mistral" du `README.md` pour la commande `vllm serve`.
33
+
34
+ > Les services restants documentés ici (orchestrateur D8s, inférence A100, ACR, CI/CD) concernent uniquement l'infrastructure de **compute** — le LLM, lui, ne dépend plus d'Azure.
35
+
36
+ ---
37
+
38
+ ## 3. Provisionnement et CI/CD (azure-pipelines.yml)
39
+
40
+ ### Différence fondamentale entre CI/CD et Provisionnement (Infrastructure as Code)
41
+ **`azure-pipelines.yml`** ne sert PAS à instancier/louer la carte graphique ou le serveur en soi.
42
+ - Son rôle est purement logiciel (CI/CD) : À chaque "Push" sur votre dépôt Git, `azure-pipelines.yml` va demander à Azure de lancer des tests unitaires, vérifier la syntaxe Python, compiler le code, et éventuellement créer une image Docker.
43
+
44
+ **Pour *Provisionner* (allumer les machines `NC-A100` et `D8s`), on utilise de l'Infrastructure-as-Code (IaC) :**
45
+ - L'idéal est de créer un fichier **Bicep** ou **Terraform** (`main.tf`).
46
+ - Ce fichier déclare formellement "TotalEnergies désire X machines virtuelles et Y bases de données dans la région France-Central".
47
+ - Il est possible d'automatiser le déploiement de cette infrastructure via `azure-pipelines.yml`, mais c'est bien le langage *Terraform* ou le portail *Azure Resource Manager (ARM)* qui loue le matériel.
48
+
49
+ ---
50
+
51
+ ## 4. Workflow de Déploiement Recommandé pour le PoC
52
+
53
+ 1. **Validation Locale** : Testez le script sur un ordinateur local/VSCode pour vous assurer de la syntaxe JAX (ce que nous avons fait).
54
+ 2. **Setup Azure AI** : Allez sur le portail Azure AI, déployez Mistral et récupérez les clés pour votre fichier `.env`.
55
+ 3. **Déploiement Docker** : Poussez votre code dans un Docker Registry Azure (`ACR - Azure Container Registry`).
56
+ 4. **Execution GPU** : Démarrez une instance `NC` (A100), connectez-vous y en SSH, tirez l'image Docker, et lancez la boucle FWI Surrogate.
@@ -0,0 +1,78 @@
1
+ Bootstrap: docker
2
+ From: python:3.12-slim
3
+
4
+ # Lightweight Apptainer image for the analyze-only mode.
5
+ # - No NVIDIA HPC SDK (CPU-only, no GPU drivers required on the host)
6
+ # - No LLM dependencies pulled in (`uv sync --no-dev` skips dev extras)
7
+ # - Pullable on any HPC login node (Pangea, GENCI, OVH, on-prem)
8
+ #
9
+ # Build:
10
+ # apptainer build coding-agent-analyze.sif Apptainer.analyze
11
+ #
12
+ # Use in a Slurm step:
13
+ # srun apptainer run coding-agent-analyze.sif \
14
+ # --format sarif --output report.sarif --fail-on error src/
15
+
16
+ %files
17
+ pyproject.toml /opt/coding-agent/pyproject.toml
18
+ uv.lock /opt/coding-agent/uv.lock
19
+ README.md /opt/coding-agent/README.md
20
+ local_code_agent /opt/coding-agent/local_code_agent
21
+
22
+ %post
23
+ set -euo pipefail
24
+ export DEBIAN_FRONTEND=noninteractive
25
+
26
+ apt-get update
27
+ apt-get install -y --no-install-recommends \
28
+ git \
29
+ ca-certificates \
30
+ curl \
31
+ build-essential \
32
+ gfortran
33
+ rm -rf /var/lib/apt/lists/*
34
+
35
+ # uv — same tool used in the dev workflow, no surprises for contributors
36
+ curl -LsSf https://astral.sh/uv/install.sh | sh
37
+ install -m 0755 /root/.local/bin/uv /usr/local/bin/uv
38
+
39
+ # Project install — skip dev extras (no jax / langchain / fastmcp on this image)
40
+ cd /opt/coding-agent
41
+ uv sync --no-dev
42
+
43
+ # Smoke-test the entry point at build time so a broken image fails fast
44
+ uv run agent-analyze --help > /dev/null
45
+
46
+ %environment
47
+ export PYTHONUNBUFFERED=1
48
+ export PATH=/opt/coding-agent/.venv/bin:$PATH
49
+
50
+ %runscript
51
+ # `apptainer run ... <args>` → forwards args straight to agent-analyze.
52
+ cd /opt/coding-agent
53
+ exec uv run agent-analyze "$@"
54
+
55
+ %labels
56
+ Author "Loïc Maurin <maurin.loic.ac@gmail.com>"
57
+ Description "coding-agent — Fortran static analyzer (Loki, no LLM, no GPU)"
58
+ Mode "analyze-only"
59
+ License "Apache-2.0"
60
+
61
+ %help
62
+ Static analyzer for legacy Fortran 90 — detects COMMON blocks, SAVE,
63
+ I/O in kernels, missing IMPLICIT NONE, POINTER/derived-type patterns,
64
+ suspected loop-carried dependencies. No LLM call, no file rewrite.
65
+
66
+ Outputs SARIF (CI-uploadable), JSON, or human-readable text.
67
+
68
+ Examples
69
+ --------
70
+ Scan a single file:
71
+ apptainer run coding-agent-analyze.sif src/kernel.f90
72
+
73
+ Emit SARIF for a Jenkins / GitLab CI step:
74
+ apptainer run coding-agent-analyze.sif \\
75
+ --format sarif --output report.sarif --fail-on error src/
76
+
77
+ Run inside a Slurm job:
78
+ srun --cpus-per-task=2 apptainer run coding-agent-analyze.sif src/