igel-qe-core 1.0.0
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.
- package/dist/cli/index.js +38 -0
- package/dist/mcp/server.js +104 -0
- package/knowledge_base/__init__.py +3 -0
- package/knowledge_base/__pycache__/__init__.cpython-314.pyc +0 -0
- package/knowledge_base/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/__pycache__/confidence.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/config.cpython-314.pyc +0 -0
- package/knowledge_base/__pycache__/config.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/config.cpython-38.pyc +0 -0
- package/knowledge_base/__pycache__/context_fusion.cpython-314.pyc +0 -0
- package/knowledge_base/__pycache__/context_fusion.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/feedback_analytics.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/feedback_applier.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/feedback_cli.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/feedback_curator.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/feedback_handler.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/generate.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/generate_qcapps134.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/input_classifier.cpython-314.pyc +0 -0
- package/knowledge_base/__pycache__/input_classifier.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/kg_extractor.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/knowledge_graph.cpython-314.pyc +0 -0
- package/knowledge_base/__pycache__/knowledge_graph.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/manual_tc_parser.cpython-314.pyc +0 -0
- package/knowledge_base/__pycache__/manual_tc_parser.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/precedence.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/prompts.cpython-314.pyc +0 -0
- package/knowledge_base/__pycache__/prompts.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/reranker.cpython-314.pyc +0 -0
- package/knowledge_base/__pycache__/reranker.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/retrieval_debug.cpython-314.pyc +0 -0
- package/knowledge_base/__pycache__/retrieval_debug.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/retriever.cpython-314.pyc +0 -0
- package/knowledge_base/__pycache__/retriever.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/server.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/tc_transformer.cpython-314.pyc +0 -0
- package/knowledge_base/__pycache__/tc_transformer.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/test_generator.cpython-314.pyc +0 -0
- package/knowledge_base/__pycache__/test_generator.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__init__.py +6 -0
- package/knowledge_base/agents/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/agents/__pycache__/fusion_agent.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/fusion_agent.cpython-38.pyc +0 -0
- package/knowledge_base/agents/__pycache__/graph.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/graph.cpython-38.pyc +0 -0
- package/knowledge_base/agents/__pycache__/healing_agent.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/intent_agent.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/intent_agent.cpython-38.pyc +0 -0
- package/knowledge_base/agents/__pycache__/kg_agent.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/kg_agent.cpython-38.pyc +0 -0
- package/knowledge_base/agents/__pycache__/memory_agent.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/memory_agent.cpython-38.pyc +0 -0
- package/knowledge_base/agents/__pycache__/rca_agent.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/reflection_agent.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/reflection_agent.cpython-38.pyc +0 -0
- package/knowledge_base/agents/__pycache__/regression_agent.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/retrieval_agent.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/retrieval_agent.cpython-38.pyc +0 -0
- package/knowledge_base/agents/__pycache__/script_agent.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/script_agent.cpython-38.pyc +0 -0
- package/knowledge_base/agents/__pycache__/state.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/state.cpython-38.pyc +0 -0
- package/knowledge_base/agents/__pycache__/temporal_agent.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/temporal_agent.cpython-38.pyc +0 -0
- package/knowledge_base/agents/__pycache__/validation_agent.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/validation_agent.cpython-38.pyc +0 -0
- package/knowledge_base/agents/automation_design_agent.py +123 -0
- package/knowledge_base/agents/code_intelligence_agent.py +147 -0
- package/knowledge_base/agents/confidence_agent.py +94 -0
- package/knowledge_base/agents/execution_validation_agent.py +129 -0
- package/knowledge_base/agents/feedback_agent.py +56 -0
- package/knowledge_base/agents/fusion_agent.py +113 -0
- package/knowledge_base/agents/graph.py +152 -0
- package/knowledge_base/agents/healing_agent.py +62 -0
- package/knowledge_base/agents/intent_agent.py +76 -0
- package/knowledge_base/agents/kg_agent.py +91 -0
- package/knowledge_base/agents/memory_agent.py +62 -0
- package/knowledge_base/agents/rca_agent.py +53 -0
- package/knowledge_base/agents/reflection_agent.py +62 -0
- package/knowledge_base/agents/regression_agent.py +81 -0
- package/knowledge_base/agents/requirement_agent.py +71 -0
- package/knowledge_base/agents/retrieval_agent.py +66 -0
- package/knowledge_base/agents/scenario_agent.py +81 -0
- package/knowledge_base/agents/script_agent.py +121 -0
- package/knowledge_base/agents/script_generator_agent.py +77 -0
- package/knowledge_base/agents/state.py +53 -0
- package/knowledge_base/agents/temporal_agent.py +48 -0
- package/knowledge_base/agents/testcase_agent.py +111 -0
- package/knowledge_base/agents/validation_agent.py +49 -0
- package/knowledge_base/agents/workflow_engine.py +87 -0
- package/knowledge_base/alembic/README.md +104 -0
- package/knowledge_base/alembic/__pycache__/env.cpython-37.pyc +0 -0
- package/knowledge_base/alembic/__pycache__/env.cpython-38.pyc +0 -0
- package/knowledge_base/alembic/env.py +76 -0
- package/knowledge_base/alembic/script.py.mako +5 -0
- package/knowledge_base/alembic/versions/.gitkeep +26 -0
- package/knowledge_base/alembic/versions/001_phase0_feedback.py +122 -0
- package/knowledge_base/alembic/versions/002_feedback_promotions.py +60 -0
- package/knowledge_base/alembic/versions/003_enterprise_hardening.py +74 -0
- package/knowledge_base/alembic/versions/__pycache__/001_phase0_feedback.cpython-37.pyc +0 -0
- package/knowledge_base/alembic/versions/__pycache__/001_phase0_feedback.cpython-38.pyc +0 -0
- package/knowledge_base/alembic/versions/__pycache__/002_feedback_promotions.cpython-37.pyc +0 -0
- package/knowledge_base/alembic/versions/__pycache__/002_feedback_promotions.cpython-38.pyc +0 -0
- package/knowledge_base/api/__init__.py +1 -0
- package/knowledge_base/api/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/api/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/api/__pycache__/middleware.cpython-38.pyc +0 -0
- package/knowledge_base/api/__pycache__/server.cpython-37.pyc +0 -0
- package/knowledge_base/api/__pycache__/server.cpython-38.pyc +0 -0
- package/knowledge_base/api/middleware.py +78 -0
- package/knowledge_base/api/server.py +778 -0
- package/knowledge_base/chunking/__init__.py +0 -0
- package/knowledge_base/chunking/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/chunking/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/chunking/__pycache__/chunker.cpython-37.pyc +0 -0
- package/knowledge_base/chunking/__pycache__/chunker.cpython-38.pyc +0 -0
- package/knowledge_base/chunking/__pycache__/validators.cpython-37.pyc +0 -0
- package/knowledge_base/chunking/__pycache__/validators.cpython-38.pyc +0 -0
- package/knowledge_base/chunking/chunker.py +402 -0
- package/knowledge_base/chunking/validators.py +144 -0
- package/knowledge_base/cli/__init__.py +1 -0
- package/knowledge_base/cli/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/cli/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/cli/__pycache__/feedback_cli.cpython-37.pyc +0 -0
- package/knowledge_base/cli/__pycache__/feedback_cli.cpython-38.pyc +0 -0
- package/knowledge_base/cli/__pycache__/generate.cpython-37.pyc +0 -0
- package/knowledge_base/cli/__pycache__/generate.cpython-38.pyc +0 -0
- package/knowledge_base/cli/__pycache__/generate_qcapps134.cpython-37.pyc +0 -0
- package/knowledge_base/cli/feedback_cli.py +121 -0
- package/knowledge_base/cli/generate.py +308 -0
- package/knowledge_base/cli/generate_qcapps134.py +391 -0
- package/knowledge_base/config/.env +100 -0
- package/knowledge_base/config/.env.example +75 -0
- package/knowledge_base/config/__init__.py +5 -0
- package/knowledge_base/config/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/config/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/config/__pycache__/settings.cpython-37.pyc +0 -0
- package/knowledge_base/config/__pycache__/settings.cpython-38.pyc +0 -0
- package/knowledge_base/config/settings.py +280 -0
- package/knowledge_base/connectors/__init__.py +5 -0
- package/knowledge_base/connectors/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/base.cpython-37.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/base.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/bitbucket_connector.cpython-37.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/bitbucket_connector.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/community_connector.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/confluence_connector.cpython-37.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/confluence_connector.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/jira_connector.cpython-37.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/jira_connector.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/kb_igel_connector.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/playwright_fetcher.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/query_bridge.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/search_backends.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/serviceNow_connector.cpython-37.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/serviceNow_connector.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/sync_scheduler.cpython-37.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/sync_scheduler.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/teamcity_connector.cpython-37.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/teamcity_connector.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/testRail_connector.cpython-37.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/testRail_connector.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/web_fetcher.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/base.py +44 -0
- package/knowledge_base/connectors/bitbucket_connector.py +25 -0
- package/knowledge_base/connectors/community_connector.py +112 -0
- package/knowledge_base/connectors/confluence_connector.py +165 -0
- package/knowledge_base/connectors/jira_connector.py +174 -0
- package/knowledge_base/connectors/kb_igel_connector.py +145 -0
- package/knowledge_base/connectors/playwright_fetcher.py +50 -0
- package/knowledge_base/connectors/query_bridge.py +170 -0
- package/knowledge_base/connectors/search_backends.py +368 -0
- package/knowledge_base/connectors/serviceNow_connector.py +25 -0
- package/knowledge_base/connectors/sync_scheduler.py +111 -0
- package/knowledge_base/connectors/teamcity_connector.py +25 -0
- package/knowledge_base/connectors/testRail_connector.py +25 -0
- package/knowledge_base/connectors/web_fetcher.py +280 -0
- package/knowledge_base/core/__init__.py +8 -0
- package/knowledge_base/core/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/core/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/core/__pycache__/cache.cpython-38.pyc +0 -0
- package/knowledge_base/core/__pycache__/circuit_breaker.cpython-38.pyc +0 -0
- package/knowledge_base/core/__pycache__/confidence.cpython-37.pyc +0 -0
- package/knowledge_base/core/__pycache__/confidence.cpython-38.pyc +0 -0
- package/knowledge_base/core/__pycache__/logging_setup.cpython-38.pyc +0 -0
- package/knowledge_base/core/__pycache__/metrics.cpython-38.pyc +0 -0
- package/knowledge_base/core/__pycache__/precedence.cpython-37.pyc +0 -0
- package/knowledge_base/core/__pycache__/precedence.cpython-38.pyc +0 -0
- package/knowledge_base/core/__pycache__/request_context.cpython-38.pyc +0 -0
- package/knowledge_base/core/cache.py +98 -0
- package/knowledge_base/core/circuit_breaker.py +33 -0
- package/knowledge_base/core/confidence.py +254 -0
- package/knowledge_base/core/logging_setup.py +39 -0
- package/knowledge_base/core/metrics.py +63 -0
- package/knowledge_base/core/precedence.py +354 -0
- package/knowledge_base/core/request_context.py +54 -0
- package/knowledge_base/db/__init__.py +0 -0
- package/knowledge_base/db/__pycache__/__init__.cpython-314.pyc +0 -0
- package/knowledge_base/db/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/db/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/db/__pycache__/client.cpython-314.pyc +0 -0
- package/knowledge_base/db/__pycache__/client.cpython-37.pyc +0 -0
- package/knowledge_base/db/__pycache__/client.cpython-38.pyc +0 -0
- package/knowledge_base/db/__pycache__/connector_sync.cpython-38.pyc +0 -0
- package/knowledge_base/db/__pycache__/feedback_schema.cpython-37.pyc +0 -0
- package/knowledge_base/db/__pycache__/feedback_schema.cpython-38.pyc +0 -0
- package/knowledge_base/db/__pycache__/kg_introspect.cpython-314.pyc +0 -0
- package/knowledge_base/db/__pycache__/kg_introspect.cpython-37.pyc +0 -0
- package/knowledge_base/db/__pycache__/kg_introspect.cpython-38.pyc +0 -0
- package/knowledge_base/db/__pycache__/schema.cpython-37.pyc +0 -0
- package/knowledge_base/db/__pycache__/schema.cpython-38.pyc +0 -0
- package/knowledge_base/db/client.py +100 -0
- package/knowledge_base/db/connector_sync.py +43 -0
- package/knowledge_base/db/feedback_schema.py +548 -0
- package/knowledge_base/db/igel_schema.py +150 -0
- package/knowledge_base/db/kg_introspect.py +116 -0
- package/knowledge_base/db/migrations.py +22 -0
- package/knowledge_base/db/schema.py +649 -0
- package/knowledge_base/deploy/Dockerfile +23 -0
- package/knowledge_base/deploy/feedback_automation.sh +18 -0
- package/knowledge_base/deploy/firecrawl-docker.sh +50 -0
- package/knowledge_base/deploy/igel-testgen.service +26 -0
- package/knowledge_base/deploy/install_reranker.sh +92 -0
- package/knowledge_base/deploy/requirements.txt +68 -0
- package/knowledge_base/deploy/run_server.sh +35 -0
- package/knowledge_base/docs/TEST_GENERATION_GUIDE.md +174 -0
- package/knowledge_base/embeddings/__init__.py +0 -0
- package/knowledge_base/embeddings/__pycache__/__init__.cpython-314.pyc +0 -0
- package/knowledge_base/embeddings/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/embeddings/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/embeddings/__pycache__/azure_embedder.cpython-314.pyc +0 -0
- package/knowledge_base/embeddings/__pycache__/azure_embedder.cpython-37.pyc +0 -0
- package/knowledge_base/embeddings/__pycache__/azure_embedder.cpython-38.pyc +0 -0
- package/knowledge_base/embeddings/azure_embedder.py +99 -0
- package/knowledge_base/eval/__init__.py +33 -0
- package/knowledge_base/eval/__main__.py +172 -0
- package/knowledge_base/eval/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/eval/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/eval/__pycache__/__main__.cpython-37.pyc +0 -0
- package/knowledge_base/eval/__pycache__/baseline.cpython-37.pyc +0 -0
- package/knowledge_base/eval/__pycache__/baseline.cpython-38.pyc +0 -0
- package/knowledge_base/eval/__pycache__/harness.cpython-37.pyc +0 -0
- package/knowledge_base/eval/__pycache__/harness.cpython-38.pyc +0 -0
- package/knowledge_base/eval/__pycache__/scorers.cpython-37.pyc +0 -0
- package/knowledge_base/eval/__pycache__/scorers.cpython-38.pyc +0 -0
- package/knowledge_base/eval/baseline.py +213 -0
- package/knowledge_base/eval/harness.py +400 -0
- package/knowledge_base/eval/queries_50.json +302 -0
- package/knowledge_base/eval/scorers.py +494 -0
- package/knowledge_base/exemplars/README.md +7 -0
- package/knowledge_base/exemplars/__pycache__/pytest_reference_snippet.cpython-37.pyc +0 -0
- package/knowledge_base/exemplars/gold_manual_concise_snippet.md +8 -0
- package/knowledge_base/exemplars/gold_manual_detailed_snippet.md +7 -0
- package/knowledge_base/exemplars/pytest_reference_snippet.py +37 -0
- package/knowledge_base/feedback/__init__.py +10 -0
- package/knowledge_base/feedback/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/feedback/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/feedback/__pycache__/analytics.cpython-37.pyc +0 -0
- package/knowledge_base/feedback/__pycache__/analytics.cpython-38.pyc +0 -0
- package/knowledge_base/feedback/__pycache__/applier.cpython-37.pyc +0 -0
- package/knowledge_base/feedback/__pycache__/applier.cpython-38.pyc +0 -0
- package/knowledge_base/feedback/__pycache__/curator.cpython-37.pyc +0 -0
- package/knowledge_base/feedback/__pycache__/curator.cpython-38.pyc +0 -0
- package/knowledge_base/feedback/__pycache__/handler.cpython-37.pyc +0 -0
- package/knowledge_base/feedback/__pycache__/handler.cpython-38.pyc +0 -0
- package/knowledge_base/feedback/analytics.py +72 -0
- package/knowledge_base/feedback/applier.py +93 -0
- package/knowledge_base/feedback/curator.py +49 -0
- package/knowledge_base/feedback/handler.py +151 -0
- package/knowledge_base/generation/__init__.py +5 -0
- package/knowledge_base/generation/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/generation/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/generation/__pycache__/input_classifier.cpython-37.pyc +0 -0
- package/knowledge_base/generation/__pycache__/input_classifier.cpython-38.pyc +0 -0
- package/knowledge_base/generation/__pycache__/manual_tc_parser.cpython-37.pyc +0 -0
- package/knowledge_base/generation/__pycache__/manual_tc_parser.cpython-38.pyc +0 -0
- package/knowledge_base/generation/__pycache__/prompts.cpython-37.pyc +0 -0
- package/knowledge_base/generation/__pycache__/prompts.cpython-38.pyc +0 -0
- package/knowledge_base/generation/__pycache__/tc_transformer.cpython-37.pyc +0 -0
- package/knowledge_base/generation/__pycache__/test_generator.cpython-37.pyc +0 -0
- package/knowledge_base/generation/__pycache__/test_generator.cpython-38.pyc +0 -0
- package/knowledge_base/generation/input_classifier.py +148 -0
- package/knowledge_base/generation/manual_tc_parser.py +180 -0
- package/knowledge_base/generation/prompts.py +755 -0
- package/knowledge_base/generation/tc_transformer.py +368 -0
- package/knowledge_base/generation/test_generator.py +553 -0
- package/knowledge_base/graph_db/__init__.py +5 -0
- package/knowledge_base/graph_db/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/graph_db/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/graph_db/__pycache__/graphiti_client.cpython-37.pyc +0 -0
- package/knowledge_base/graph_db/__pycache__/kg_traversal.cpython-37.pyc +0 -0
- package/knowledge_base/graph_db/__pycache__/migrate_kg.cpython-37.pyc +0 -0
- package/knowledge_base/graph_db/__pycache__/neo4j_client.cpython-37.pyc +0 -0
- package/knowledge_base/graph_db/__pycache__/neo4j_client.cpython-38.pyc +0 -0
- package/knowledge_base/graph_db/__pycache__/schema.cpython-37.pyc +0 -0
- package/knowledge_base/graph_db/__pycache__/temporal_ingest.cpython-37.pyc +0 -0
- package/knowledge_base/graph_db/graphiti_client.py +127 -0
- package/knowledge_base/graph_db/kg_traversal.py +192 -0
- package/knowledge_base/graph_db/migrate_kg.py +93 -0
- package/knowledge_base/graph_db/neo4j_client.py +116 -0
- package/knowledge_base/graph_db/schema.py +22 -0
- package/knowledge_base/graph_db/temporal_ingest.py +59 -0
- package/knowledge_base/ingestion/__init__.py +1 -0
- package/knowledge_base/ingestion/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/ingestion/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/ingestion/__pycache__/ingest.cpython-37.pyc +0 -0
- package/knowledge_base/ingestion/__pycache__/ingest.cpython-38.pyc +0 -0
- package/knowledge_base/ingestion/__pycache__/ingest_images.cpython-37.pyc +0 -0
- package/knowledge_base/ingestion/__pycache__/ingest_images.cpython-38.pyc +0 -0
- package/knowledge_base/ingestion/__pycache__/kg_extractor.cpython-37.pyc +0 -0
- package/knowledge_base/ingestion/__pycache__/kg_extractor.cpython-38.pyc +0 -0
- package/knowledge_base/ingestion/__pycache__/web_ingest.cpython-38.pyc +0 -0
- package/knowledge_base/ingestion/ingest.py +346 -0
- package/knowledge_base/ingestion/ingest_images.py +330 -0
- package/knowledge_base/ingestion/kg_extractor.py +358 -0
- package/knowledge_base/ingestion/web_ingest.py +83 -0
- package/knowledge_base/intelligence/__init__.py +1 -0
- package/knowledge_base/intelligence/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/intelligence/__pycache__/execution_ingest.cpython-37.pyc +0 -0
- package/knowledge_base/intelligence/__pycache__/predictive_engine.cpython-37.pyc +0 -0
- package/knowledge_base/intelligence/__pycache__/risk_scorer.cpython-37.pyc +0 -0
- package/knowledge_base/intelligence/execution_ingest.py +34 -0
- package/knowledge_base/intelligence/predictive_engine.py +7 -0
- package/knowledge_base/intelligence/risk_scorer.py +8 -0
- package/knowledge_base/memory/__init__.py +6 -0
- package/knowledge_base/memory/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/memory/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/memory/__pycache__/cognee_client.cpython-37.pyc +0 -0
- package/knowledge_base/memory/__pycache__/cognee_client.cpython-38.pyc +0 -0
- package/knowledge_base/memory/__pycache__/ingest_memory.cpython-37.pyc +0 -0
- package/knowledge_base/memory/__pycache__/memory_types.cpython-37.pyc +0 -0
- package/knowledge_base/memory/__pycache__/memory_types.cpython-38.pyc +0 -0
- package/knowledge_base/memory/cognee_client.py +164 -0
- package/knowledge_base/memory/ingest_memory.py +60 -0
- package/knowledge_base/memory/memory_types.py +23 -0
- package/knowledge_base/models/test_requirement.py +84 -0
- package/knowledge_base/parsers/__init__.py +0 -0
- package/knowledge_base/parsers/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/parsers/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/parsers/__pycache__/csv_parser.cpython-37.pyc +0 -0
- package/knowledge_base/parsers/__pycache__/csv_parser.cpython-38.pyc +0 -0
- package/knowledge_base/parsers/__pycache__/doc_parser.cpython-37.pyc +0 -0
- package/knowledge_base/parsers/__pycache__/doc_parser.cpython-38.pyc +0 -0
- package/knowledge_base/parsers/__pycache__/html_parser.cpython-38.pyc +0 -0
- package/knowledge_base/parsers/__pycache__/image_extractor.cpython-37.pyc +0 -0
- package/knowledge_base/parsers/__pycache__/image_extractor.cpython-38.pyc +0 -0
- package/knowledge_base/parsers/__pycache__/markdown_parser.cpython-37.pyc +0 -0
- package/knowledge_base/parsers/__pycache__/markdown_parser.cpython-38.pyc +0 -0
- package/knowledge_base/parsers/__pycache__/pdf_parser.cpython-37.pyc +0 -0
- package/knowledge_base/parsers/__pycache__/pdf_parser.cpython-38.pyc +0 -0
- package/knowledge_base/parsers/csv_parser.py +126 -0
- package/knowledge_base/parsers/doc_parser.py +176 -0
- package/knowledge_base/parsers/html_parser.py +151 -0
- package/knowledge_base/parsers/image_extractor.py +370 -0
- package/knowledge_base/parsers/markdown_parser.py +116 -0
- package/knowledge_base/parsers/pdf_parser.py +178 -0
- package/knowledge_base/retrieval/__init__.py +1 -0
- package/knowledge_base/retrieval/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/context_fusion.cpython-37.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/context_fusion.cpython-38.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/knowledge_graph.cpython-37.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/knowledge_graph.cpython-38.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/reranker.cpython-37.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/reranker.cpython-38.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/retrieval_debug.cpython-37.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/retrieval_debug.cpython-38.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/retriever.cpython-37.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/retriever.cpython-38.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/unified_query.cpython-38.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/web_retriever.cpython-38.pyc +0 -0
- package/knowledge_base/retrieval/context_fusion.py +264 -0
- package/knowledge_base/retrieval/knowledge_graph.py +267 -0
- package/knowledge_base/retrieval/reranker.py +308 -0
- package/knowledge_base/retrieval/retrieval_debug.py +69 -0
- package/knowledge_base/retrieval/retriever.py +885 -0
- package/knowledge_base/retrieval/unified_query.py +189 -0
- package/knowledge_base/retrieval/web_retriever.py +337 -0
- package/knowledge_base/validators/__init__.py +1 -0
- package/knowledge_base/validators/__pycache__/__init__.cpython-314.pyc +0 -0
- package/knowledge_base/validators/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/validators/__pycache__/step_fidelity.cpython-314.pyc +0 -0
- package/knowledge_base/validators/__pycache__/step_fidelity.cpython-37.pyc +0 -0
- package/knowledge_base/validators/step_fidelity.py +88 -0
- package/knowledge_base/vision/__init__.py +0 -0
- package/knowledge_base/vision/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/vision/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/vision/__pycache__/image_describer.cpython-37.pyc +0 -0
- package/knowledge_base/vision/__pycache__/image_describer.cpython-38.pyc +0 -0
- package/knowledge_base/vision/image_describer.py +202 -0
- package/package.json +31 -0
|
@@ -0,0 +1,755 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Prompt templates for IGEL test case generation.
|
|
3
|
+
|
|
4
|
+
Provides:
|
|
5
|
+
build_system_prompt() → static IGEL expert system prompt
|
|
6
|
+
assemble_context_window() → fit KB chunks into token budget
|
|
7
|
+
build_markdown_user_prompt() → prompt for detailed markdown test doc
|
|
8
|
+
build_python_user_prompt() → prompt for pytest Python file
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import logging
|
|
13
|
+
from dataclasses import dataclass
|
|
14
|
+
|
|
15
|
+
from knowledge_base.config import cfg
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
MAX_CONTEXT_TOKENS = int(getattr(cfg, "CONTEXT_TOKEN_BUDGET", 8000))
|
|
20
|
+
_CHARS_PER_TOKEN = 3.8 # conservative estimate, avoids importing tiktoken here
|
|
21
|
+
|
|
22
|
+
# Exact import block generated tests must use — injected verbatim into Python prompt
|
|
23
|
+
_REQUIRED_IMPORTS = """\
|
|
24
|
+
import time, allure
|
|
25
|
+
import pytest
|
|
26
|
+
from core.api.UMS import UMS
|
|
27
|
+
from core.api.ums_wums_api import UMSWUMSApi
|
|
28
|
+
from core.api.auth_token import UMSAuthTokenService
|
|
29
|
+
from core.ssh.ssh import SSHClient
|
|
30
|
+
from core.ui.ui_automation_text import OcrUiInteractor
|
|
31
|
+
from bussiness.page_login import ums_login
|
|
32
|
+
from config.read_config import ums_cred, device_cred, otp_secrets_cred, root_path
|
|
33
|
+
from core.ssh.my_logger import logger
|
|
34
|
+
from bussiness.onepassword_otp import OTPGenerator"""
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# ── Data Model ────────────────────────────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
@dataclass
|
|
40
|
+
class PromptContext:
|
|
41
|
+
topic: str
|
|
42
|
+
test_id: str
|
|
43
|
+
feature_area: str
|
|
44
|
+
product: str | None
|
|
45
|
+
context_chunks: list # list[SearchResult] — avoid circular import
|
|
46
|
+
token_budget: int = MAX_CONTEXT_TOKENS
|
|
47
|
+
kg_context_block: str = ""
|
|
48
|
+
image_context_block: str = ""
|
|
49
|
+
web_context_block: str = ""
|
|
50
|
+
mcp_context_block: str = ""
|
|
51
|
+
memory_context_block: str = ""
|
|
52
|
+
temporal_context_block: str = ""
|
|
53
|
+
skip_assemble_window: bool = False
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# ── Public API ────────────────────────────────────────────────────────────────
|
|
57
|
+
|
|
58
|
+
def build_system_prompt() -> str:
|
|
59
|
+
return _SYSTEM_PROMPT
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def assemble_context_window(
|
|
63
|
+
results: list,
|
|
64
|
+
token_budget: int = MAX_CONTEXT_TOKENS,
|
|
65
|
+
) -> tuple[list, int]:
|
|
66
|
+
"""
|
|
67
|
+
Fit retrieved parent_content chunks into the token budget.
|
|
68
|
+
Prioritises higher rrf_score results. Truncates last chunk at word boundary if needed.
|
|
69
|
+
Returns (selected_results, estimated_tokens_used).
|
|
70
|
+
"""
|
|
71
|
+
reserve = 800 # headroom for prompt template text
|
|
72
|
+
available = token_budget - reserve
|
|
73
|
+
|
|
74
|
+
def _rank_key(r) -> tuple[float, float]:
|
|
75
|
+
rr = getattr(r, "rerank_score", None)
|
|
76
|
+
if rr is not None:
|
|
77
|
+
return (-float(rr), -float(getattr(r, "rrf_score", 0.0)))
|
|
78
|
+
return (-float(getattr(r, "rrf_score", 0.0)), 0.0)
|
|
79
|
+
|
|
80
|
+
ordered = sorted(results, key=_rank_key)
|
|
81
|
+
|
|
82
|
+
selected = []
|
|
83
|
+
used = 0
|
|
84
|
+
|
|
85
|
+
for result in ordered:
|
|
86
|
+
chunk_tokens = _estimate_tokens(result.parent_content)
|
|
87
|
+
if used + chunk_tokens <= available:
|
|
88
|
+
selected.append(result)
|
|
89
|
+
used += chunk_tokens
|
|
90
|
+
elif available - used > 200:
|
|
91
|
+
# Truncate at word boundary to fill remaining space
|
|
92
|
+
remaining_chars = int((available - used) * _CHARS_PER_TOKEN)
|
|
93
|
+
truncated_content = _truncate_at_word(result.parent_content, remaining_chars)
|
|
94
|
+
# Create a shallow copy with truncated content
|
|
95
|
+
import copy
|
|
96
|
+
r = copy.copy(result)
|
|
97
|
+
r.parent_content = truncated_content + "\n[...truncated]"
|
|
98
|
+
selected.append(r)
|
|
99
|
+
used += _estimate_tokens(truncated_content)
|
|
100
|
+
break
|
|
101
|
+
else:
|
|
102
|
+
break
|
|
103
|
+
|
|
104
|
+
logger.debug("Context window: %d chunks, ~%d tokens", len(selected), used)
|
|
105
|
+
return selected, used
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def build_markdown_user_prompt(ctx: PromptContext) -> str:
|
|
109
|
+
if ctx.skip_assemble_window:
|
|
110
|
+
selected = list(ctx.context_chunks)
|
|
111
|
+
tokens_used = sum(_estimate_tokens(r.parent_content) for r in selected)
|
|
112
|
+
else:
|
|
113
|
+
selected, tokens_used = assemble_context_window(ctx.context_chunks, ctx.token_budget)
|
|
114
|
+
|
|
115
|
+
prefix_parts: list[str] = []
|
|
116
|
+
if getattr(ctx, "kg_context_block", "") and ctx.kg_context_block.strip():
|
|
117
|
+
prefix_parts.append(ctx.kg_context_block.strip())
|
|
118
|
+
if getattr(ctx, "image_context_block", "") and ctx.image_context_block.strip():
|
|
119
|
+
prefix_parts.append(ctx.image_context_block.strip())
|
|
120
|
+
if getattr(ctx, "web_context_block", "") and ctx.web_context_block.strip():
|
|
121
|
+
prefix_parts.append(ctx.web_context_block.strip())
|
|
122
|
+
if getattr(ctx, "mcp_context_block", "") and ctx.mcp_context_block.strip():
|
|
123
|
+
prefix_parts.append(ctx.mcp_context_block.strip())
|
|
124
|
+
if getattr(ctx, "memory_context_block", "") and ctx.memory_context_block.strip():
|
|
125
|
+
prefix_parts.append(ctx.memory_context_block.strip())
|
|
126
|
+
if getattr(ctx, "temporal_context_block", "") and ctx.temporal_context_block.strip():
|
|
127
|
+
prefix_parts.append(ctx.temporal_context_block.strip())
|
|
128
|
+
|
|
129
|
+
context_block = _format_context_block(selected)
|
|
130
|
+
if prefix_parts:
|
|
131
|
+
context_block = "\n\n".join(prefix_parts) + "\n\n" + context_block
|
|
132
|
+
|
|
133
|
+
sources = kb_sources_for_prompt(selected)
|
|
134
|
+
sources_short = ", ".join(dict.fromkeys(r.file_name for r in selected)) or "IGEL documentation"
|
|
135
|
+
|
|
136
|
+
return f"""Generate a JIRA-level detailed IGEL test case document using the knowledge base context below.
|
|
137
|
+
|
|
138
|
+
TEST REQUEST
|
|
139
|
+
============
|
|
140
|
+
Test ID : {ctx.test_id}
|
|
141
|
+
Topic : {ctx.topic}
|
|
142
|
+
Feature Area : {ctx.feature_area}
|
|
143
|
+
Product : {ctx.product or "IGEL OS 12"}
|
|
144
|
+
KB Sources : {sources_short}
|
|
145
|
+
KB traceability (IDs; same as SOURCE n / KB_REF in context): {sources}
|
|
146
|
+
|
|
147
|
+
KNOWLEDGE BASE CONTEXT
|
|
148
|
+
======================
|
|
149
|
+
{context_block}
|
|
150
|
+
|
|
151
|
+
INSTRUCTIONS
|
|
152
|
+
============
|
|
153
|
+
Using the context above, generate a complete JIRA-style test case. Match the exact level of
|
|
154
|
+
detail shown in IGEL JIRA tickets — specific TC Setup navigation paths, exact CLI commands,
|
|
155
|
+
precise expected results with exact UI element names.
|
|
156
|
+
|
|
157
|
+
The user's ask may be short (e.g. "SSO test steps"); ALWAYS produce the FULL detailed document
|
|
158
|
+
below — never a summary-only or bullet sketch. Depth must reflect what the KB passages support.
|
|
159
|
+
|
|
160
|
+
EXECUTABLE STEP QUALITY (NON-NEGOTIABLE)
|
|
161
|
+
----------------------------------------
|
|
162
|
+
- Each TEST DATA sub-step must state WHO does WHAT WHERE: product surface (UMS Web, device session,
|
|
163
|
+
SSH shell, browser), exact control names, literal values to set or type.
|
|
164
|
+
- Every EXPECTED RESULT must name a concrete check (exact strings, exit code, journal line,
|
|
165
|
+
screenshot-level detail). If the KB gives an exact log pattern or UI label, reproduce it verbatim.
|
|
166
|
+
- Do NOT use filler phrases alone as expected results (e.g. "Pass", "OK", "Works as expected").
|
|
167
|
+
- Copy navigation paths, CLI, registry-style keys, file paths, and URLs from SOURCE/KB_REF blocks
|
|
168
|
+
when present; do not substitute generic equivalents.
|
|
169
|
+
- If the KB does not contain enough detail for a safe step, omit that step and note in
|
|
170
|
+
Additional Information that the KB did not specify it — do not guess.
|
|
171
|
+
|
|
172
|
+
OUTPUT FORMAT
|
|
173
|
+
=============
|
|
174
|
+
|
|
175
|
+
# {ctx.test_id}: {ctx.topic}
|
|
176
|
+
|
|
177
|
+
## Key Details
|
|
178
|
+
| Field | Value |
|
|
179
|
+
|-------|-------|
|
|
180
|
+
| JIRA ID | {ctx.test_id} |
|
|
181
|
+
| Category | (infer from feature area and context) |
|
|
182
|
+
| Priority | High |
|
|
183
|
+
| Type | (Integration / Functional / Hardware-dependent — infer from context) |
|
|
184
|
+
| Feature Area | {ctx.feature_area} |
|
|
185
|
+
| Product | {ctx.product or "IGEL OS 12"} |
|
|
186
|
+
| Source Documents | {sources_short} |
|
|
187
|
+
|
|
188
|
+
## Description
|
|
189
|
+
(2-3 sentences: what feature is tested, what this test validates, why it matters)
|
|
190
|
+
|
|
191
|
+
## Additional Information
|
|
192
|
+
(Key technical notes as bullet points — include:
|
|
193
|
+
- default values and what they mean
|
|
194
|
+
- important config file paths like /etc/chromium-browser/... or /var/log/...
|
|
195
|
+
- policy names and parameter names from context
|
|
196
|
+
- any warnings or platform-specific notes from context)
|
|
197
|
+
|
|
198
|
+
## Requirements
|
|
199
|
+
- IGEL OS version: (from context)
|
|
200
|
+
- UMS version: (from context)
|
|
201
|
+
- (any app version requirements from context)
|
|
202
|
+
|
|
203
|
+
## Preconditions
|
|
204
|
+
(Bullet list — be specific. Example: "IGEL OS 12 device registered in UMS with online status confirmed in UMS console")
|
|
205
|
+
|
|
206
|
+
## TC Setup — Configuration Navigation Paths
|
|
207
|
+
(List all UMS/device configuration steps using the exact path format:
|
|
208
|
+
`TC Setup > [Section] > [SubSection] > [Setting] = [value]`
|
|
209
|
+
Example: `TC Setup: Apps > Zoom > Zoom Sessions > Session Name = "Test_Session"`)
|
|
210
|
+
|
|
211
|
+
## Test Details
|
|
212
|
+
|
|
213
|
+
### Test Step Table
|
|
214
|
+
Three columns: **STEP** | **TEST DATA** | **EXPECTED RESULT**
|
|
215
|
+
|
|
216
|
+
| # | STEP | TEST DATA | EXPECTED RESULT |
|
|
217
|
+
|---|------|-----------|-----------------|
|
|
218
|
+
|
|
219
|
+
For each step:
|
|
220
|
+
- STEP: Brief title of what is being verified (e.g., "Check Hardware Video Acceleration")
|
|
221
|
+
- TEST DATA: Numbered sub-steps with exact actions. Include:
|
|
222
|
+
* TC Setup navigation paths: `TC Setup: Apps > [App] > [Setting] = true/false`
|
|
223
|
+
* Exact CLI commands with full syntax: `ps ax | grep process-name`
|
|
224
|
+
* Exact file paths: `/var/log/user/app.log`
|
|
225
|
+
* Specific URLs for verification: `chrome://media-internals`
|
|
226
|
+
* Policy/config values: `HardwareAccelerationModeEnabled`
|
|
227
|
+
- EXPECTED RESULT: Specific verifiable outcomes. Include:
|
|
228
|
+
* Exact UI elements visible (e.g., "Home, Chat, Meetings, Contacts tabs visible")
|
|
229
|
+
* Exact log output expected (e.g., "journalctl shows no errors for process X")
|
|
230
|
+
* Specific commands and their expected output
|
|
231
|
+
* Pass/fail criterion with exact wording
|
|
232
|
+
|
|
233
|
+
Generate as many test steps as the KB context and KG entities justify — do not pad with
|
|
234
|
+
vague or invented steps. Each step must have at least 2 concrete sub-steps in TEST DATA.
|
|
235
|
+
If no manual TC is provided, derive all steps from the Knowledge Base passages and KG nodes
|
|
236
|
+
retrieved above; use the exact registry keys, UI paths, and CLI commands found there.
|
|
237
|
+
|
|
238
|
+
## Cleanup
|
|
239
|
+
| Step | Action | Command/Navigation | Verification |
|
|
240
|
+
|------|--------|--------------------|-------------|
|
|
241
|
+
(Specific cleanup steps — detach profiles, reboot, verify clean state)
|
|
242
|
+
|
|
243
|
+
## Troubleshooting
|
|
244
|
+
| # | Issue | Symptoms | Root Cause | Fix |
|
|
245
|
+
|---|-------|----------|------------|-----|
|
|
246
|
+
(Minimum 3 specific issues from context — include exact diagnostic commands)
|
|
247
|
+
|
|
248
|
+
Generate the complete document now. Use specific IGEL terminology, exact navigation paths,
|
|
249
|
+
real CLI commands, and concrete expected values. Never write "TBD" or "[add here]"."""
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def format_kb_context_excerpt_for_python(results: list, max_chars: int = 7500) -> str:
|
|
253
|
+
"""Ground pytest generation in the same KB text as markdown (truncated for token limits)."""
|
|
254
|
+
if not results:
|
|
255
|
+
return "(No KB chunks — do not invent product steps.)"
|
|
256
|
+
body = _format_context_block(results)
|
|
257
|
+
if len(body) <= max_chars:
|
|
258
|
+
return body
|
|
259
|
+
truncated = _truncate_at_word(body, max_chars)
|
|
260
|
+
return (
|
|
261
|
+
truncated
|
|
262
|
+
+ "\n\n[...KB excerpt truncated for token budget; strings and paths above remain "
|
|
263
|
+
"authoritative for implementation.]\n"
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def build_python_user_prompt(ctx: PromptContext, markdown_content: str) -> str:
|
|
268
|
+
test_id_upper = ctx.test_id.upper()
|
|
269
|
+
slug = _slugify(ctx.topic)
|
|
270
|
+
filename = f"test_{ctx.test_id}_{slug}.py"
|
|
271
|
+
# Extract step count hint from markdown — use actual count, no artificial floor
|
|
272
|
+
step_count = markdown_content.lower().count("#### step") or markdown_content.lower().count("| # |") or 0
|
|
273
|
+
|
|
274
|
+
kb_excerpt = format_kb_context_excerpt_for_python(ctx.context_chunks)
|
|
275
|
+
extra_context = []
|
|
276
|
+
if getattr(ctx, "kg_context_block", "") and ctx.kg_context_block.strip():
|
|
277
|
+
extra_context.append(ctx.kg_context_block.strip())
|
|
278
|
+
if getattr(ctx, "web_context_block", "") and ctx.web_context_block.strip():
|
|
279
|
+
extra_context.append(ctx.web_context_block.strip())
|
|
280
|
+
if getattr(ctx, "mcp_context_block", "") and ctx.mcp_context_block.strip():
|
|
281
|
+
extra_context.append(ctx.mcp_context_block.strip())
|
|
282
|
+
extra_block = "\n\n".join(extra_context)
|
|
283
|
+
|
|
284
|
+
return f"""Generate a Python pytest file for the following IGEL test case.
|
|
285
|
+
|
|
286
|
+
KNOWLEDGE BASE CONTEXT (PostgreSQL RAG — ground truth; implement only behavior supported here)
|
|
287
|
+
================================================================================
|
|
288
|
+
{extra_block + chr(10) + chr(10) if extra_block else ""}{kb_excerpt}
|
|
289
|
+
|
|
290
|
+
SPECIFICATION (from markdown test case or topic summary)
|
|
291
|
+
=========================================================
|
|
292
|
+
{markdown_content[:4000]}
|
|
293
|
+
|
|
294
|
+
Implement step logic that matches BOTH the specification table AND the KB context above: use the
|
|
295
|
+
same navigation strings, shell commands, file paths, policy names, and on-screen text the KB shows.
|
|
296
|
+
Do not add product-specific steps absent from the KB. Steps must be executable with this project's
|
|
297
|
+
fixtures (UMS, WUMS, SSH, OCR) — no vague asserts.
|
|
298
|
+
|
|
299
|
+
STRICT REQUIREMENTS — follow exactly, no deviations
|
|
300
|
+
=====================================================
|
|
301
|
+
|
|
302
|
+
1. FILE NAME: {filename}
|
|
303
|
+
|
|
304
|
+
2. MODULE DOCSTRING (copy this template exactly):
|
|
305
|
+
\"\"\"
|
|
306
|
+
Test ID : {ctx.test_id}
|
|
307
|
+
Title : {ctx.topic}
|
|
308
|
+
Feature : {ctx.feature_area}
|
|
309
|
+
Product : {ctx.product or "IGEL OS 12"}
|
|
310
|
+
Description: [1-sentence description from specification above]
|
|
311
|
+
Author : IGEL QA Automation (AI-Generated)
|
|
312
|
+
\"\"\"
|
|
313
|
+
|
|
314
|
+
3. IMPORTS — copy these verbatim, do not add or remove any:
|
|
315
|
+
{_REQUIRED_IMPORTS}
|
|
316
|
+
|
|
317
|
+
4. MODULE-LEVEL (after imports):
|
|
318
|
+
click = OcrUiInteractor()
|
|
319
|
+
|
|
320
|
+
5. HELPER FUNCTIONS:
|
|
321
|
+
def get_ssh():
|
|
322
|
+
return SSHClient(host=device_cred["host"], user=device_cred["user"],
|
|
323
|
+
pwd=device_cred["pwd"], port=device_cred["port"])
|
|
324
|
+
|
|
325
|
+
def _assign(ums, wums, device, profile_key, default_name, api_config):
|
|
326
|
+
profile = ums.get_profile_details(api_config.get(profile_key, default_name))
|
|
327
|
+
wums.assign_object(device["id"], profile["id"], "profile")
|
|
328
|
+
return profile
|
|
329
|
+
|
|
330
|
+
def _detach(ums, wums, device, profile_key, default_name, api_config):
|
|
331
|
+
profile = ums.get_profile_details(api_config.get(profile_key, default_name))
|
|
332
|
+
wums.detach_profile(device["id"], profile["id"])
|
|
333
|
+
|
|
334
|
+
6. STEP FUNCTIONS — generate {step_count if step_count > 0 else "one step per test scenario found in"} the specification above + 1 cleanup:
|
|
335
|
+
- Decorator: @allure.step("{test_id_upper} SN: [short description]")
|
|
336
|
+
- Signature: def {test_id_upper}_stepN(api_config, browser): -> bool
|
|
337
|
+
- Body pattern:
|
|
338
|
+
try:
|
|
339
|
+
ums = UMS(ums_cred["base_url"], ums_cred["username"], ums_cred["password"])
|
|
340
|
+
wums = UMSWUMSApi(ums_cred["weburl"], ums_cred["username"], ums_cred["password"])
|
|
341
|
+
dev = ums.get_vm_details(device_cred["hostname"])
|
|
342
|
+
[step implementation from specification]
|
|
343
|
+
return True / return result_bool
|
|
344
|
+
except Exception as e:
|
|
345
|
+
logger.error(f"{test_id_upper}_stepN: {{e}}"); return False
|
|
346
|
+
|
|
347
|
+
- Cleanup: @allure.step("{test_id_upper} Cleanup: [description]")
|
|
348
|
+
def {test_id_upper}_cleanup(api_config): -> bool
|
|
349
|
+
|
|
350
|
+
7. TEST FUNCTIONS — one per step, SINGLE LINE each:
|
|
351
|
+
@allure.feature("{ctx.feature_area}")
|
|
352
|
+
@allure.severity(allure.severity_level.CRITICAL)
|
|
353
|
+
def test_{ctx.test_id}_step1(api_config, browser_instance): assert {test_id_upper}_step1(api_config, browser_instance)
|
|
354
|
+
|
|
355
|
+
@allure.feature("{ctx.feature_area}")
|
|
356
|
+
@allure.severity(allure.severity_level.CRITICAL)
|
|
357
|
+
def test_{ctx.test_id}_step2(api_config, browser_instance): assert {test_id_upper}_step2(api_config, browser_instance)
|
|
358
|
+
|
|
359
|
+
[continue for each step, then:]
|
|
360
|
+
|
|
361
|
+
@allure.feature("{ctx.feature_area}")
|
|
362
|
+
@allure.severity(allure.severity_level.MINOR)
|
|
363
|
+
def test_{ctx.test_id}_cleanup(api_config): assert {test_id_upper}_cleanup(api_config)
|
|
364
|
+
|
|
365
|
+
8. RULES:
|
|
366
|
+
- ALL configurable values from api_config dict — NEVER hardcode IPs, passwords, or secrets
|
|
367
|
+
- Use ums_cred["base_url"], ums_cred["weburl"], device_cred — for hosts/URLs not in those dicts,
|
|
368
|
+
use string literals ONLY when they appear verbatim in the KB context (e.g. chrome:// URLs,
|
|
369
|
+
fixed IGEL paths). Never use example.com or guessed tenant URLs.
|
|
370
|
+
- Use click.is_text_present_on_screen() and click.click_text_on_screen() for OCR checks — pass
|
|
371
|
+
the exact visible strings from KB/spec, not paraphrases
|
|
372
|
+
- Use ssh.exec("command") with the exact commands from KB/spec (full flags/paths)
|
|
373
|
+
- Every step function returns bool; each step must encode a concrete observable check
|
|
374
|
+
- No TODO comments, no placeholder text, no "verify success" without a named check
|
|
375
|
+
- No additional imports beyond the verbatim block above
|
|
376
|
+
|
|
377
|
+
Generate the complete Python file now. Output raw Python only — no markdown fences."""
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
# ── Internal Helpers ──────────────────────────────────────────────────────────
|
|
381
|
+
|
|
382
|
+
def _estimate_tokens(text: str) -> int:
|
|
383
|
+
return int(len(text) / _CHARS_PER_TOKEN)
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
def _truncate_at_word(text: str, max_chars: int) -> str:
|
|
387
|
+
if len(text) <= max_chars:
|
|
388
|
+
return text
|
|
389
|
+
truncated = text[:max_chars]
|
|
390
|
+
last_space = truncated.rfind(" ")
|
|
391
|
+
return truncated[:last_space] if last_space > 0 else truncated
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
def kb_trace_lines(results: list) -> list[str]:
|
|
395
|
+
"""One trace string per retrieved parent context (same order as SOURCE n / KB_REF)."""
|
|
396
|
+
lines: list[str] = []
|
|
397
|
+
for i, r in enumerate(results, start=1):
|
|
398
|
+
doc = getattr(r, "document_id", "") or "—"
|
|
399
|
+
parent = getattr(r, "parent_chunk_id", "") or "—"
|
|
400
|
+
child = getattr(r, "child_chunk_id", "") or "—"
|
|
401
|
+
sec = getattr(r, "section_title", "") or "—"
|
|
402
|
+
fn = getattr(r, "file_name", "") or "—"
|
|
403
|
+
lines.append(
|
|
404
|
+
f"[KB_REF {i}] file={fn} | section={sec} | document_id={doc} | "
|
|
405
|
+
f"parent_chunk_id={parent} | child_chunk_id={child}"
|
|
406
|
+
)
|
|
407
|
+
return lines
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
def kb_sources_for_prompt(results: list) -> str:
|
|
411
|
+
"""Compact ID list for the prompt header (same KB_REF order as context blocks)."""
|
|
412
|
+
if not results:
|
|
413
|
+
return "IGEL documentation"
|
|
414
|
+
return "; ".join(kb_trace_lines(results))
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
def format_kb_retrieval_references_markdown(results: list) -> str:
|
|
418
|
+
"""Appendix for generated markdown: exact chunk traceability for cross-checking the KB."""
|
|
419
|
+
if not results:
|
|
420
|
+
return ""
|
|
421
|
+
rows = [
|
|
422
|
+
"| KB_REF | File | Section | document_id | parent_chunk_id | child_chunk_id | RRF | Rerank |",
|
|
423
|
+
"|--------|------|---------|-------------|-----------------|----------------|-----|--------|",
|
|
424
|
+
]
|
|
425
|
+
for i, r in enumerate(results, start=1):
|
|
426
|
+
rr = getattr(r, "rerank_score", None)
|
|
427
|
+
rr_s = f"{rr:.4f}" if rr is not None else "—"
|
|
428
|
+
sec = (getattr(r, "section_title", None) or "").replace("|", "\\|")
|
|
429
|
+
fn = (getattr(r, "file_name", None) or "").replace("|", "\\|")
|
|
430
|
+
rows.append(
|
|
431
|
+
f"| {i} | {fn} | {sec} | `{getattr(r, 'document_id', '')}` | "
|
|
432
|
+
f"`{getattr(r, 'parent_chunk_id', '')}` | `{getattr(r, 'child_chunk_id', '')}` | "
|
|
433
|
+
f"{getattr(r, 'rrf_score', 0.0):.4f} | {rr_s} |"
|
|
434
|
+
)
|
|
435
|
+
note = (
|
|
436
|
+
"\n*These rows match the `SOURCE n` / `KB_REF` blocks in the knowledge base context "
|
|
437
|
+
"sent to the model. Use `parent_chunk_id` / `document_id` to locate rows in PostgreSQL "
|
|
438
|
+
"(`kb_parent_chunks`, `kb_documents`).*\n"
|
|
439
|
+
)
|
|
440
|
+
return "## KB retrieval traceability\n\n" + "\n".join(rows) + note
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
def format_kb_retrieval_references_python_comment(results: list) -> str:
|
|
444
|
+
"""Trailing comment block for generated pytest files (traceability)."""
|
|
445
|
+
if not results:
|
|
446
|
+
return ""
|
|
447
|
+
lines = ["# --- KB retrieval references (cross-check in DB / ingest logs) ---"]
|
|
448
|
+
for i, r in enumerate(results, start=1):
|
|
449
|
+
lines.append(
|
|
450
|
+
f"# [KB_REF {i}] file={getattr(r, 'file_name', '')!r} "
|
|
451
|
+
f"section={getattr(r, 'section_title', '')!r} "
|
|
452
|
+
f"document_id={getattr(r, 'document_id', '')!r} "
|
|
453
|
+
f"parent_chunk_id={getattr(r, 'parent_chunk_id', '')!r} "
|
|
454
|
+
f"child_chunk_id={getattr(r, 'child_chunk_id', '')!r}"
|
|
455
|
+
)
|
|
456
|
+
return "\n\n" + "\n".join(lines) + "\n"
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
def _format_context_block(results: list) -> str:
|
|
460
|
+
if not results:
|
|
461
|
+
return "(No relevant KB content found)"
|
|
462
|
+
parts = []
|
|
463
|
+
for i, r in enumerate(results, start=1):
|
|
464
|
+
rr_tail = (
|
|
465
|
+
f" | Rerank: {r.rerank_score:.4f}"
|
|
466
|
+
if getattr(r, "rerank_score", None) is not None
|
|
467
|
+
else ""
|
|
468
|
+
)
|
|
469
|
+
parts.append(
|
|
470
|
+
f"=== SOURCE {i} (KB_REF={i}) | {r.section_title or r.file_name} ===\n"
|
|
471
|
+
f"document_id={r.document_id}\n"
|
|
472
|
+
f"parent_chunk_id={r.parent_chunk_id}\n"
|
|
473
|
+
f"child_chunk_id={r.child_chunk_id}\n"
|
|
474
|
+
f"Product: {r.product} | File: {r.file_name} | Section: {r.section_title or '—'} | "
|
|
475
|
+
f"Type: {r.chunk_type} | Relevance_RRF: {r.rrf_score:.4f}{rr_tail}\n\n"
|
|
476
|
+
f"{r.parent_content.strip()}"
|
|
477
|
+
)
|
|
478
|
+
return "\n\n" + "\n\n---\n\n".join(parts) + "\n"
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
def _slugify(text: str) -> str:
|
|
482
|
+
import re
|
|
483
|
+
slug = text.lower()
|
|
484
|
+
slug = re.sub(r"[^a-z0-9\s]", "", slug)
|
|
485
|
+
slug = re.sub(r"\s+", "_", slug.strip())
|
|
486
|
+
return slug[:50]
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
# ── Gold / partial TC modes (fidelity-first) ─────────────────────────────────
|
|
490
|
+
|
|
491
|
+
TRANSFORM_SYSTEM_ADDON = """
|
|
492
|
+
|
|
493
|
+
MODE: MANUAL TEST CASE TRANSFORMATION (not authoring)
|
|
494
|
+
======================================================
|
|
495
|
+
The user supplied an official IGEL manual test. Your job is to REPACKAGE it into the template format
|
|
496
|
+
and (when asked) pytest structure — NOT to invent new scenarios, edge cases, or extra steps.
|
|
497
|
+
Preserve step count and order. Use supplementary KB text only to clarify terms already present.
|
|
498
|
+
"""
|
|
499
|
+
|
|
500
|
+
EXPAND_SYSTEM_ADDON = """
|
|
501
|
+
|
|
502
|
+
MODE: PARTIAL TEST CASE EXPANSION
|
|
503
|
+
=================================
|
|
504
|
+
The user supplied an incomplete JIRA/manual TC. Keep every original step and phrase intact in the output.
|
|
505
|
+
Add ONLY missing expected results, preconditions, or clarifying sub-steps where the description implies them.
|
|
506
|
+
Use KB context to ground new text. Do not replace or remove original steps.
|
|
507
|
+
"""
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
def load_pytest_exemplar(max_chars: int = 6000) -> str:
|
|
511
|
+
"""Few-shot excerpt from a known-good generated/hand-written pytest file."""
|
|
512
|
+
from pathlib import Path
|
|
513
|
+
p = Path(__file__).resolve().parent / "exemplars" / "pytest_reference_snippet.py"
|
|
514
|
+
if not p.exists():
|
|
515
|
+
return ""
|
|
516
|
+
text = p.read_text(encoding="utf-8", errors="replace")
|
|
517
|
+
if len(text) <= max_chars:
|
|
518
|
+
return text
|
|
519
|
+
return text[:max_chars] + "\n# [...truncated exemplar]\n"
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
def format_parsed_steps_table(steps: list) -> str:
|
|
523
|
+
"""Markdown table from ParsedStep list."""
|
|
524
|
+
if not steps:
|
|
525
|
+
return "(no parsed steps)"
|
|
526
|
+
rows = [
|
|
527
|
+
"| # | Step | Test Data | Expected Result |",
|
|
528
|
+
"|---|------|-----------|-----------------|",
|
|
529
|
+
]
|
|
530
|
+
for s in steps:
|
|
531
|
+
def _cell(x: str, lim: int) -> str:
|
|
532
|
+
t = (x or "").replace("\n", " ").replace("|", "\\|").strip()
|
|
533
|
+
return t[:lim] + ("…" if len(t) > lim else "")
|
|
534
|
+
|
|
535
|
+
rows.append(
|
|
536
|
+
f"| {_cell(s.step_id, 12)} | {_cell(s.step_title, 80)} | "
|
|
537
|
+
f"{_cell(s.test_data, 220)} | {_cell(s.expected_result, 120)} |"
|
|
538
|
+
)
|
|
539
|
+
return "\n".join(rows)
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
def build_transform_markdown_user_prompt(
|
|
543
|
+
*,
|
|
544
|
+
test_id: str,
|
|
545
|
+
feature_area: str,
|
|
546
|
+
product: str | None,
|
|
547
|
+
source_tc_full: str,
|
|
548
|
+
supplementary_context: str,
|
|
549
|
+
detail_note: str,
|
|
550
|
+
) -> str:
|
|
551
|
+
return f"""Convert the OFFICIAL IGEL manual test case below into the project's JIRA-style Markdown template.
|
|
552
|
+
|
|
553
|
+
CRITICAL — FIDELITY FIRST
|
|
554
|
+
=========================
|
|
555
|
+
- The ORIGINAL MANUAL TEST CASE section is the SOURCE OF TRUTH.
|
|
556
|
+
- Preserve EVERY step's intent, order, and scope. Do NOT add scenarios, negative tests, or steps not in the source.
|
|
557
|
+
- Do NOT remove steps. Do NOT merge unless the source explicitly combines them in one line.
|
|
558
|
+
- Refine wording only for readability; keep TC Setup paths, CLI, URLs, registry keys, and expected outcomes aligned with the source.
|
|
559
|
+
- The final Test Step Table must allow 1:1 traceability to the original step list.
|
|
560
|
+
|
|
561
|
+
Detail target: {detail_note}
|
|
562
|
+
|
|
563
|
+
ORIGINAL MANUAL TEST CASE
|
|
564
|
+
=========================
|
|
565
|
+
{source_tc_full.strip()}
|
|
566
|
+
|
|
567
|
+
SUPPLEMENTARY KB CONTEXT (use only to clarify terms present in the source; never add unrelated test ideas)
|
|
568
|
+
==================================================================================
|
|
569
|
+
{supplementary_context.strip() if supplementary_context.strip() else "(none)"}
|
|
570
|
+
|
|
571
|
+
OUTPUT METADATA (use in Key Details)
|
|
572
|
+
====================================
|
|
573
|
+
Test ID : {test_id}
|
|
574
|
+
Feature Area : {feature_area}
|
|
575
|
+
Product : {product or "IGEL OS 12"}
|
|
576
|
+
|
|
577
|
+
Produce: Key Details, Description, Preconditions, TC Setup, Test Step Table (STEP | TEST DATA | EXPECTED RESULT),
|
|
578
|
+
Additional Information, Requirements, Cleanup, Troubleshooting — following the same section expectations as standard generation.
|
|
579
|
+
"""
|
|
580
|
+
|
|
581
|
+
def build_expand_markdown_user_prompt(
|
|
582
|
+
*,
|
|
583
|
+
test_id: str,
|
|
584
|
+
topic: str,
|
|
585
|
+
feature_area: str,
|
|
586
|
+
product: str | None,
|
|
587
|
+
source_tc_full: str,
|
|
588
|
+
parsed_steps_table: str,
|
|
589
|
+
kb_context_block: str,
|
|
590
|
+
kg_image_prefix: str,
|
|
591
|
+
detail_note: str,
|
|
592
|
+
) -> str:
|
|
593
|
+
prefix = kg_image_prefix.strip()
|
|
594
|
+
body = kb_context_block.strip()
|
|
595
|
+
context = f"{prefix}\n\n{body}".strip() if prefix else body
|
|
596
|
+
return f"""Expand this PARTIAL IGEL test case into a complete JIRA-style Markdown document.
|
|
597
|
+
|
|
598
|
+
RULES
|
|
599
|
+
=====
|
|
600
|
+
- Reproduce EVERY original line/step from the partial TC; keep titles and actions verbatim where possible.
|
|
601
|
+
- Fill gaps: missing Expected Results, Preconditions, or TC Setup paths using ONLY the knowledge context below.
|
|
602
|
+
- If KB does not support a detail, write "Not specified in KB — manual confirmation required" instead of inventing.
|
|
603
|
+
- Do not add unrelated scenarios.
|
|
604
|
+
|
|
605
|
+
Detail target: {detail_note}
|
|
606
|
+
|
|
607
|
+
PARTIAL TEST CASE (raw)
|
|
608
|
+
=======================
|
|
609
|
+
{source_tc_full.strip()}
|
|
610
|
+
|
|
611
|
+
PARSED STEPS (reference)
|
|
612
|
+
========================
|
|
613
|
+
{parsed_steps_table}
|
|
614
|
+
|
|
615
|
+
TOPIC / SUMMARY
|
|
616
|
+
===============
|
|
617
|
+
{topic}
|
|
618
|
+
|
|
619
|
+
KNOWLEDGE CONTEXT (RAG + KG + images)
|
|
620
|
+
=====================================
|
|
621
|
+
{context if context else "(no retrieval — expand from source only)"}
|
|
622
|
+
|
|
623
|
+
OUTPUT METADATA
|
|
624
|
+
===============
|
|
625
|
+
Test ID : {test_id}
|
|
626
|
+
Feature Area : {feature_area}
|
|
627
|
+
Product : {product or "IGEL OS 12"}
|
|
628
|
+
|
|
629
|
+
Generate the full Markdown document with the standard sections and a complete Test Step Table.
|
|
630
|
+
"""
|
|
631
|
+
|
|
632
|
+
def build_transform_python_user_prompt(
|
|
633
|
+
*,
|
|
634
|
+
test_id: str,
|
|
635
|
+
topic: str,
|
|
636
|
+
feature_area: str,
|
|
637
|
+
product: str | None,
|
|
638
|
+
markdown_spec: str,
|
|
639
|
+
exemplar_py: str,
|
|
640
|
+
) -> str:
|
|
641
|
+
"""Python generation after transform markdown — reuses structure from build_python_user_prompt."""
|
|
642
|
+
slug = _slugify(topic)
|
|
643
|
+
filename = f"test_{test_id}_{slug}.py"
|
|
644
|
+
test_id_upper = test_id.upper()
|
|
645
|
+
step_count = max(markdown_spec.lower().count("#### step"), markdown_spec.count("|") // 3, 3)
|
|
646
|
+
|
|
647
|
+
exemplar_block = exemplar_py.strip() if exemplar_py.strip() else "(see standard import pattern in instructions)"
|
|
648
|
+
|
|
649
|
+
return f"""Generate a Python pytest file that implements EXACTLY the manual flow in the specification below.
|
|
650
|
+
|
|
651
|
+
FIDELITY
|
|
652
|
+
========
|
|
653
|
+
- Implement one step function per logical step in the Markdown spec (same order). Do not add exploratory or negative tests.
|
|
654
|
+
- Each step should reflect the Test Data and Expected Result from the spec.
|
|
655
|
+
- Use api_config / ums_cred / device_cred — never hardcode secrets.
|
|
656
|
+
|
|
657
|
+
REFERENCE EXAMPLE (shape and style only — do not copy unrelated scenarios)
|
|
658
|
+
==========================================================================
|
|
659
|
+
```python
|
|
660
|
+
{exemplar_block[:5500]}
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
SPECIFICATION
|
|
664
|
+
=============
|
|
665
|
+
{markdown_spec[:6500]}
|
|
666
|
+
|
|
667
|
+
STRICT REQUIREMENTS
|
|
668
|
+
===================
|
|
669
|
+
1. FILE NAME: {filename}
|
|
670
|
+
|
|
671
|
+
2. MODULE DOCSTRING:
|
|
672
|
+
\"\"\"
|
|
673
|
+
Test ID : {test_id}
|
|
674
|
+
Title : {topic}
|
|
675
|
+
Feature : {feature_area}
|
|
676
|
+
Product : {product or "IGEL OS 12"}
|
|
677
|
+
Description: Mapped from official IGEL manual TC (fidelity mode)
|
|
678
|
+
Author : IGEL QA Automation (AI-Generated)
|
|
679
|
+
\"\"\"
|
|
680
|
+
|
|
681
|
+
3. IMPORTS — copy verbatim:
|
|
682
|
+
{_REQUIRED_IMPORTS}
|
|
683
|
+
|
|
684
|
+
4. After imports: click = OcrUiInteractor()
|
|
685
|
+
|
|
686
|
+
5. Helpers: get_ssh(), _assign(...), _detach(...) as in standard generator.
|
|
687
|
+
|
|
688
|
+
6. Generate approximately {step_count} step functions + 1 cleanup. Each step returns bool.
|
|
689
|
+
|
|
690
|
+
7. TEST FUNCTIONS: single-line assert per step; @allure.feature("{feature_area}")
|
|
691
|
+
|
|
692
|
+
Output raw Python only — no markdown fences.
|
|
693
|
+
"""
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
# ── System Prompt ─────────────────────────────────────────────────────────────
|
|
697
|
+
|
|
698
|
+
_SYSTEM_PROMPT = """\
|
|
699
|
+
You are a senior IGEL QA automation engineer with deep expertise in testing IGEL products.
|
|
700
|
+
Your job is to generate precise, complete, and executable test cases based ONLY on the
|
|
701
|
+
documentation context provided. Never invent steps, settings, or expected values not
|
|
702
|
+
explicitly present in the context.
|
|
703
|
+
|
|
704
|
+
IGEL PRODUCT KNOWLEDGE
|
|
705
|
+
======================
|
|
706
|
+
- UMS (Universal Management Suite): Central device management server. REST API on HTTPS port 8443.
|
|
707
|
+
URL pattern: https://<ums-ip>:8443/umsapi/v3/. Used to manage profiles, assign them to devices,
|
|
708
|
+
and issue commands (reboot, factory reset). Web UI at https://<ums-ip>:8443/webapp/.
|
|
709
|
+
- IGEL OS 12: Linux-based thin client operating system. SSH accessible as root on port 22.
|
|
710
|
+
Device can be controlled via UMS API (profiles) and directly via SSH commands.
|
|
711
|
+
- COSMOS: Cloud-based management platform for IGEL devices (cloud alternative to on-prem UMS).
|
|
712
|
+
- ICG (IGEL Cloud Gateway): Secure reverse proxy allowing UMS to communicate with devices
|
|
713
|
+
outside the corporate network without VPN.
|
|
714
|
+
- IMI (IGEL Management Interface): REST API for programmatic UMS control (token-based auth).
|
|
715
|
+
- SSO Providers: Entra ID (Microsoft Azure AD), Okta, PingOne, Omnissa Horizon.
|
|
716
|
+
|
|
717
|
+
TEST AUTOMATION FRAMEWORK
|
|
718
|
+
=========================
|
|
719
|
+
- Python + pytest with Allure reporting
|
|
720
|
+
- UMS class: core.api.UMS — manages device/profile assignments via REST
|
|
721
|
+
- UMSWUMSApi class: core.api.ums_wums_api — assign/detach profiles, device operations
|
|
722
|
+
- SSHClient: core.ssh.ssh — execute shell commands on IGEL device via SSH
|
|
723
|
+
- OcrUiInteractor (click): core.ui.ui_automation_text — OCR-based screen validation and interaction
|
|
724
|
+
- ums_login: bussiness.page_login — Playwright browser automation for UMS Web UI
|
|
725
|
+
- OTPGenerator: bussiness.onepassword_otp — TOTP generation for MFA flows
|
|
726
|
+
- Configuration: config.read_config — ums_cred, device_cred, otp_secrets_cred, root_path
|
|
727
|
+
- api_config: loaded from testdata/sso/api_config.yaml["igel"] — profile names, usernames, etc.
|
|
728
|
+
|
|
729
|
+
GENERATION RULES
|
|
730
|
+
================
|
|
731
|
+
1. Use ONLY the provided KB context passages. If a step is not in the context, do not include it.
|
|
732
|
+
2. ALL configurable values (profile names, URLs, usernames) come from api_config["key"] or
|
|
733
|
+
ums_cred/device_cred dicts. NEVER hardcode actual IPs, passwords, or credentials.
|
|
734
|
+
3. For markdown: follow the template structure exactly with all required sections and tables.
|
|
735
|
+
4. For Python: step functions MUST return bool; test functions MUST be single-line assert calls.
|
|
736
|
+
5. Be specific: use actual IGEL terminology, SSH commands, and OCR check patterns from context.
|
|
737
|
+
6. Cleanup steps are mandatory — always detach profiles and reboot the device.
|
|
738
|
+
|
|
739
|
+
DETAILED & EXECUTABLE STEPS (MANDATORY)
|
|
740
|
+
=======================================
|
|
741
|
+
- Answer the user's topic with the MOST DETAILED test flow the KB allows — whether they asked for
|
|
742
|
+
"high-level steps", "test steps", or "detailed steps", always expand into full executable steps.
|
|
743
|
+
- Every step MUST be something a tester can run without interpretation: exact menu paths, exact CLI
|
|
744
|
+
with full syntax, exact file paths, exact policy/parameter names, exact UI strings to look for.
|
|
745
|
+
- FORBIDDEN vague wording: "verify it works", "ensure proper behavior", "check configuration",
|
|
746
|
+
"validate the setup", "confirm success", "test the feature" without naming WHAT is observed WHERE.
|
|
747
|
+
- REQUIRED: each EXPECTED RESULT ties to an observable (visible label, log line, command output,
|
|
748
|
+
HTTP status, file content snippet, API field) copied from or clearly implied by the KB context.
|
|
749
|
+
- URLs and URI schemes: ONLY use URLs, deep links, and browser/chrome internal URLs that appear in
|
|
750
|
+
the KB context (or standard patterns documented there, e.g. UMS port 8443 paths). NEVER invent
|
|
751
|
+
placeholder URLs (no example.com, no made-up tenant hostnames). For tenant-specific endpoints,
|
|
752
|
+
express hosts via ums_cred / api_config in generated code; in markdown describe the pattern.
|
|
753
|
+
- General platform knowledge may clarify HOW to run a command already in context, but must not add
|
|
754
|
+
new product-specific claims or paths not supported by the retrieved passages.
|
|
755
|
+
"""
|