Skip to content

Commit 9dcdc78

Browse files
committed
Auto-commit: Add saidata generation metadata tracking and schema enhancements
- Added saidata metadata section to schema 0.3 with model, generation_date, generation_time, test_date, and human_review_date fields - Enhanced generation engine to automatically inject metadata during saidata generation - Updated CLI commands (generate, update, batch) to pass model name for metadata tracking - Added saidata/ directory to .gitignore to prevent accidental commits - Updated devcontainer base image from Python 3.11-slim to Ubuntu 24.04 - Fixed git auto-commit hook to use --no-pager flag for git diff
1 parent eaefbf0 commit 9dcdc78

10 files changed

Lines changed: 140 additions & 7 deletions

File tree

.devcontainer/Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM python:3.11-slim
1+
FROM ubuntu:24.04
22

33
# Set environment variables
44
ENV PYTHONUNBUFFERED=1 \
@@ -21,6 +21,7 @@ RUN apt-get update && apt-get install -y \
2121
jq \
2222
tree \
2323
htop \
24+
python3 \
2425
ca-certificates \
2526
gnupg \
2627
lsb-release \

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ cython_debug/
163163
.sai/
164164
*.cache
165165
cache/
166+
saidata/
166167

167168
# Auto-generated version files (setuptools-scm)
168169
*/_version.py
@@ -199,4 +200,4 @@ logs/
199200
htmlcov/
200201
.pytest_cache/
201202
test-results/
202-
llm-comparison*
203+
llm-comparison*

.kiro/hooks/git-auto-commit.kiro.hook

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@
1111
},
1212
"then": {
1313
"type": "askAgent",
14-
"prompt": "Files have been modified in the workspace. Please:\n1. Update CHANGELOG\n2. Run `git add .` to stage all changes\n3. Run `git commit -m \"Auto-commit: [describe the changes]\"` with an appropriate commit message describing what was changed\n"
14+
"prompt": "Files have been modified in the workspace. Please:\n1. Update CHANGELOG. When runnging git diff use the --no-pager option\n2. Run `git add .` to stage all changes\n3. Run `git commit -m \"Auto-commit: [describe the changes]\"` with an appropriate commit message describing what was changed\n"
1515
}
1616
}

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
## [Unreleased]
99

1010
### Added
11+
- **Saidata Generation Metadata**: Added comprehensive metadata tracking for generated saidata files
12+
- New `saidata` metadata section in saidata-0.3-schema.json with model, generation_date, generation_time, test_date, and human_review_date fields
13+
- Automatic metadata injection during saidata generation with LLM model name and ISO 8601 timestamps
14+
- Generation time tracking in seconds for performance monitoring
15+
- Support for test and human review date tracking for lifecycle management
16+
- **Saidata Directory Exclusion**: Added `saidata/` to .gitignore to prevent accidental commits of generated saidata files
17+
- **Development Container Update**: Updated devcontainer base image from Python 3.11-slim to Ubuntu 24.04 for better compatibility
1118
- **Repository Search Relevance Scoring**: Implemented intelligent search result ranking system
1219
- New `_calculate_relevance_score()` method in UniversalRepositoryDownloader for scoring search results
1320
- Exact name matches score 100, name prefix matches score 50, name contains query scores 25, description matches score 5
@@ -232,6 +239,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
232239
- **Security Enhancements**: File size limits for provider YAML files to prevent DoS attacks
233240

234241
### Changed
242+
- **Generation Engine Metadata Handling**: Enhanced save_saidata method to accept optional model_name parameter for metadata injection
243+
- **CLI Commands Metadata Integration**: Updated generate, update, and batch commands to pass model name to save_saidata for proper metadata tracking
244+
- **Git Auto-Commit Hook**: Updated hook prompt to include --no-pager flag for git diff commands
235245
- **Repository Search Implementation**: Refactored search logic for better performance and accuracy
236246
- Search now applies limit at manager level instead of CLI level for better efficiency
237247
- Removed redundant limit application in CLI after manager already limits results

saigen/cli/commands/generate.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,9 @@ def generate(
259259
async def run_generation():
260260
result = await engine.generate_saidata(request)
261261
if result.success:
262-
await engine.save_saidata(result.saidata, output)
262+
# Get model name from the result
263+
model_name = engine._get_model_name(result.llm_provider_used)
264+
await engine.save_saidata(result.saidata, output, model_name=model_name)
263265
return result
264266

265267
result = asyncio.run(run_generation())

saigen/cli/commands/update.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,9 @@ async def run_update():
201201
if result.success:
202202
# Save updated saidata
203203
async def save_result():
204-
await generation_engine.save_saidata(result.saidata, output_path)
204+
# Get model name from the result
205+
model_name = generation_engine._get_model_name(result.llm_provider_used)
206+
await generation_engine.save_saidata(result.saidata, output_path, model_name=model_name)
205207

206208
asyncio.run(save_result())
207209

saigen/core/batch_engine.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,11 @@ async def process_software(software_name: str) -> GenerationResult:
300300
# Save to file if successful and output directory specified
301301
if result.success and result.saidata and request.output_directory:
302302
output_path = self._get_output_path(software_name, request.output_directory)
303-
await self.generation_engine.save_saidata(result.saidata, output_path)
303+
# Get model name from the result
304+
model_name = self.generation_engine._get_model_name(result.llm_provider_used)
305+
await self.generation_engine.save_saidata(
306+
result.saidata, output_path, model_name=model_name
307+
)
304308

305309
# Update progress
306310
progress_reporter.update(result.success, software_name)

saigen/core/generation_engine.py

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,19 @@ async def generate_saidata(self, request: GenerationRequest) -> GenerationResult
231231
llm_response.content, request.software_name, context, provider_name
232232
)
233233

234+
# Add generation metadata
235+
from datetime import datetime, timezone
236+
237+
from ..models.saidata import SaidataMetadata
238+
239+
if not saidata.saidata:
240+
saidata.saidata = SaidataMetadata()
241+
242+
# Get model name from config (always returns a non-empty string)
243+
model_name = self._get_model_name(provider_name)
244+
saidata.saidata.model = model_name
245+
saidata.saidata.generation_date = datetime.now(timezone.utc).isoformat()
246+
234247
# Apply URL validation filter if enabled
235248
if self.enable_url_filter:
236249
if self.logger:
@@ -244,6 +257,10 @@ async def generate_saidata(self, request: GenerationRequest) -> GenerationResult
244257

245258
generation_time = time.time() - start_time
246259

260+
# Add generation time to metadata
261+
if saidata.saidata:
262+
saidata.saidata.generation_time = round(generation_time, 2)
263+
247264
result = GenerationResult(
248265
success=True,
249266
saidata=saidata,
@@ -1228,12 +1245,44 @@ def _update_metrics(self, llm_response) -> None:
12281245
if llm_response.cost_estimate:
12291246
self._total_cost += llm_response.cost_estimate
12301247

1231-
async def save_saidata(self, saidata: SaiData, output_path: Path) -> None:
1248+
def _get_model_name(self, provider_name: str) -> str:
1249+
"""Get the model name for a given provider.
1250+
1251+
Args:
1252+
provider_name: Name of the LLM provider
1253+
1254+
Returns:
1255+
Model name or provider name if model not found
1256+
"""
1257+
# Try to get from config
1258+
if self.config and "llm_providers" in self.config:
1259+
llm_providers = self.config["llm_providers"]
1260+
if provider_name in llm_providers:
1261+
provider_config = llm_providers[provider_name]
1262+
if isinstance(provider_config, dict) and "model" in provider_config:
1263+
model = provider_config["model"]
1264+
if model: # Only return if not None or empty
1265+
return model
1266+
1267+
# Try from config object
1268+
if self.config_obj and hasattr(self.config_obj, "llm_providers"):
1269+
if provider_name in self.config_obj.llm_providers:
1270+
provider_config = self.config_obj.llm_providers[provider_name]
1271+
if hasattr(provider_config, "model") and provider_config.model:
1272+
return provider_config.model
1273+
1274+
# Fallback to provider name (always return something)
1275+
return provider_name if provider_name else "unknown"
1276+
1277+
async def save_saidata(
1278+
self, saidata: SaiData, output_path: Path, model_name: Optional[str] = None
1279+
) -> None:
12321280
"""Save saidata to file.
12331281
12341282
Args:
12351283
saidata: SaiData instance to save
12361284
output_path: Path to save the file
1285+
model_name: Name of the LLM model used for generation (optional)
12371286
12381287
Raises:
12391288
GenerationEngineError: If saving fails
@@ -1246,6 +1295,17 @@ async def save_saidata(self, saidata: SaiData, output_path: Path) -> None:
12461295
# Ensure output directory exists
12471296
output_path.parent.mkdir(parents=True, exist_ok=True)
12481297

1298+
# Add generation metadata if model_name is provided
1299+
if model_name:
1300+
from datetime import datetime, timezone
1301+
1302+
from ..models.saidata import SaidataMetadata
1303+
1304+
if not saidata.saidata:
1305+
saidata.saidata = SaidataMetadata()
1306+
saidata.saidata.model = model_name
1307+
saidata.saidata.generation_date = datetime.now(timezone.utc).isoformat()
1308+
12491309
# Convert to dict and save as YAML
12501310
data = saidata.model_dump(exclude_none=True)
12511311

@@ -1259,12 +1319,24 @@ async def save_saidata(self, saidata: SaiData, output_path: Path) -> None:
12591319
"output_path": str(output_path),
12601320
"file_size_bytes": file_size,
12611321
"providers_count": len(saidata.providers) if saidata.providers else 0,
1322+
"model_name": model_name,
12621323
}
12631324
)
12641325
else:
12651326
# Ensure output directory exists
12661327
output_path.parent.mkdir(parents=True, exist_ok=True)
12671328

1329+
# Add generation metadata if model_name is provided
1330+
if model_name:
1331+
from datetime import datetime, timezone
1332+
1333+
from ..models.saidata import SaidataMetadata
1334+
1335+
if not saidata.saidata:
1336+
saidata.saidata = SaidataMetadata()
1337+
saidata.saidata.model = model_name
1338+
saidata.saidata.generation_date = datetime.now(timezone.utc).isoformat()
1339+
12681340
# Convert to dict and save as YAML
12691341
data = saidata.model_dump(exclude_none=True)
12701342

saigen/models/saidata.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,11 +358,22 @@ class Compatibility(BaseModel):
358358
versions: Optional[VersionCompatibility] = None
359359

360360

361+
class SaidataMetadata(BaseModel):
362+
"""Metadata about the saidata file generation and lifecycle."""
363+
364+
model: Optional[str] = None
365+
generation_date: Optional[str] = None
366+
generation_time: Optional[float] = None
367+
test_date: Optional[str] = None
368+
human_review_date: Optional[str] = None
369+
370+
361371
class SaiData(BaseModel):
362372
"""Complete SaiData structure."""
363373

364374
version: str = Field(default="0.3", pattern=r"^\d+\.\d+(\.\d+)?$")
365375
metadata: Metadata
376+
saidata: Optional[SaidataMetadata] = None
366377
packages: Optional[List[Package]] = None
367378
services: Optional[List[Service]] = None
368379
files: Optional[List[File]] = None

schemas/saidata-0.3-schema.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,36 @@
5555
"name"
5656
]
5757
},
58+
"saidata": {
59+
"type": "object",
60+
"description": "Metadata about the saidata file generation and lifecycle",
61+
"properties": {
62+
"model": {
63+
"type": "string",
64+
"description": "Name of the LLM model used to generate this saidata"
65+
},
66+
"generation_date": {
67+
"type": "string",
68+
"format": "date-time",
69+
"description": "ISO 8601 timestamp when this saidata was generated"
70+
},
71+
"generation_time": {
72+
"type": "number",
73+
"description": "Time taken to generate this saidata in seconds",
74+
"minimum": 0
75+
},
76+
"test_date": {
77+
"type": "string",
78+
"format": "date-time",
79+
"description": "ISO 8601 timestamp when this saidata was last tested"
80+
},
81+
"human_review_date": {
82+
"type": "string",
83+
"format": "date-time",
84+
"description": "ISO 8601 timestamp when this saidata was last reviewed by a human"
85+
}
86+
}
87+
},
5888
"packages": {
5989
"type": "array",
6090
"description": "Default package definitions that apply across providers",

0 commit comments

Comments
 (0)