decomposer: fix validation failure for Migrate the kab_ingestion domain models, ports, GitHub SCM connector, and SharePoint CMS connector into the repository's app/ package.; Wire the migrated ingestion components into the agent application entry point, card, settings, triggers, governance, publication, and validation layers.; Populate every remaining placeholder file with working application, package, test, dependency, and Kubernetes content.; Verify the migrated agent and completed repository end to end.
Some checks failed
quality-gates / verify (push) Failing after 7s
Some checks failed
quality-gates / verify (push) Failing after 7s
This commit is contained in:
5
app/kab_ingestion/__init__.py
Normal file
5
app/kab_ingestion/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
"""Ingestion domain migrated into the application package."""
|
||||
|
||||
from .domain.models import IngestionRequest, IngestionResult, SourceDocument
|
||||
|
||||
__all__ = ["IngestionRequest", "IngestionResult", "SourceDocument"]
|
||||
6
app/kab_ingestion/connectors/__init__.py
Normal file
6
app/kab_ingestion/connectors/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
"""Concrete ingestion connectors."""
|
||||
|
||||
from .github import GitHubSCMConnector
|
||||
from .sharepoint import SharePointCMSConnector
|
||||
|
||||
__all__ = ["GitHubSCMConnector", "SharePointCMSConnector"]
|
||||
32
app/kab_ingestion/connectors/github.py
Normal file
32
app/kab_ingestion/connectors/github.py
Normal file
@@ -0,0 +1,32 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from dataclasses import dataclass
|
||||
from urllib.request import Request, urlopen
|
||||
|
||||
from ..domain.models import IngestionRequest, SourceDocument
|
||||
|
||||
|
||||
@dataclass
|
||||
class GitHubSCMConnector:
|
||||
token: str | None = None
|
||||
api_base: str = "https://api.github.com"
|
||||
|
||||
def fetch(self, request: IngestionRequest) -> list[SourceDocument]:
|
||||
"""Fetch a file or repository contents using the GitHub contents API."""
|
||||
url = request.locator if request.locator.startswith("http") else f"{self.api_base}/{request.locator.lstrip('/')}"
|
||||
headers = {"Accept": "application/vnd.github+json", "User-Agent": "content-ingestion-agent"}
|
||||
if self.token:
|
||||
headers["Authorization"] = f"Bearer {self.token}"
|
||||
with urlopen(Request(url, headers=headers), timeout=20) as response:
|
||||
payload = json.loads(response.read().decode("utf-8"))
|
||||
items = payload if isinstance(payload, list) else [payload]
|
||||
return [self._document(item, request) for item in items if item.get("type", "file") == "file"]
|
||||
|
||||
@staticmethod
|
||||
def _document(item: dict, request: IngestionRequest) -> SourceDocument:
|
||||
body = item.get("content", "")
|
||||
if item.get("encoding") == "base64":
|
||||
import base64
|
||||
body = base64.b64decode(body).decode("utf-8", errors="replace")
|
||||
return SourceDocument(identifier=str(item.get("sha", item.get("path", "unknown"))), title=item.get("name", item.get("path", "Untitled")), body=body, source=request.source, url=item.get("html_url"), metadata={"path": item.get("path")})
|
||||
22
app/kab_ingestion/connectors/sharepoint.py
Normal file
22
app/kab_ingestion/connectors/sharepoint.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from dataclasses import dataclass
|
||||
from urllib.request import Request, urlopen
|
||||
|
||||
from ..domain.models import SourceDocument
|
||||
|
||||
|
||||
@dataclass
|
||||
class SharePointCMSConnector:
|
||||
site_url: str
|
||||
access_token: str
|
||||
|
||||
def publish(self, document: SourceDocument) -> str:
|
||||
"""Create a SharePoint list item through Microsoft Graph."""
|
||||
endpoint = f"{self.site_url.rstrip('/')}/_api/web/lists/getbytitle('Knowledge')/items"
|
||||
payload = json.dumps({"Title": document.title, "Content": document.body}).encode()
|
||||
request = Request(endpoint, data=payload, method="POST", headers={"Authorization": f"Bearer {self.access_token}", "Accept": "application/json", "Content-Type": "application/json"})
|
||||
with urlopen(request, timeout=20) as response:
|
||||
result = json.loads(response.read().decode("utf-8"))
|
||||
return result.get("d", {}).get("Id", result.get("id", document.identifier))
|
||||
5
app/kab_ingestion/domain/__init__.py
Normal file
5
app/kab_ingestion/domain/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
"""Typed ingestion domain contracts."""
|
||||
|
||||
from .models import IngestionRequest, IngestionResult, SourceDocument
|
||||
|
||||
__all__ = ["IngestionRequest", "IngestionResult", "SourceDocument"]
|
||||
37
app/kab_ingestion/domain/models.py
Normal file
37
app/kab_ingestion/domain/models.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any
|
||||
|
||||
|
||||
def utc_now() -> datetime:
|
||||
return datetime.now(timezone.utc)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class IngestionRequest:
|
||||
source: str
|
||||
locator: str
|
||||
requested_by: str = "system"
|
||||
metadata: dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SourceDocument:
|
||||
identifier: str
|
||||
title: str
|
||||
body: str
|
||||
source: str
|
||||
url: str | None = None
|
||||
metadata: dict[str, Any] = field(default_factory=dict)
|
||||
fetched_at: datetime = field(default_factory=utc_now)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class IngestionResult:
|
||||
document: SourceDocument
|
||||
accepted: bool
|
||||
status: str
|
||||
reason: str | None = None
|
||||
published_url: str | None = None
|
||||
6
app/kab_ingestion/ports/__init__.py
Normal file
6
app/kab_ingestion/ports/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
"""Ports implemented by source and publication adapters."""
|
||||
|
||||
from .cms import CMSConnector
|
||||
from .scm import SCMConnector
|
||||
|
||||
__all__ = ["CMSConnector", "SCMConnector"]
|
||||
9
app/kab_ingestion/ports/cms.py
Normal file
9
app/kab_ingestion/ports/cms.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from typing import Protocol
|
||||
|
||||
from ..domain.models import SourceDocument
|
||||
|
||||
|
||||
class CMSConnector(Protocol):
|
||||
"""Publish normalized source documents to a content system."""
|
||||
|
||||
def publish(self, document: SourceDocument) -> str: ...
|
||||
9
app/kab_ingestion/ports/scm.py
Normal file
9
app/kab_ingestion/ports/scm.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from typing import Protocol
|
||||
|
||||
from ..domain.models import IngestionRequest, SourceDocument
|
||||
|
||||
|
||||
class SCMConnector(Protocol):
|
||||
"""Retrieve documents from a source-control system."""
|
||||
|
||||
def fetch(self, request: IngestionRequest) -> list[SourceDocument]: ...
|
||||
Reference in New Issue
Block a user