Combines three repositories into a single workspace: - go-agent → pkg/orchestrator (Clotho), pkg/jobrunner, pkg/loop, cmd/ - go-agentic → pkg/lifecycle (allowance, sessions, plans, dispatch) - php-devops → repos.yaml, setup.sh, scripts/, .core/ Module path: forge.lthn.ai/core/agent All packages build, all tests pass. Co-Authored-By: Virgil <virgil@lethean.io>
147 lines
4 KiB
Go
147 lines
4 KiB
Go
package lifecycle
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
|
|
"forge.lthn.ai/core/go-log"
|
|
)
|
|
|
|
// ScoreContentRequest is the payload for content scoring.
|
|
type ScoreContentRequest struct {
|
|
Text string `json:"text"`
|
|
Prompt string `json:"prompt,omitempty"`
|
|
}
|
|
|
|
// ScoreImprintRequest is the payload for linguistic imprint analysis.
|
|
type ScoreImprintRequest struct {
|
|
Text string `json:"text"`
|
|
}
|
|
|
|
// ScoreResult holds the response from the scoring engine.
|
|
// The shape is proxied from the EaaS Go binary, so fields are dynamic.
|
|
type ScoreResult map[string]any
|
|
|
|
// ScoreHealthResponse holds the health check result.
|
|
type ScoreHealthResponse struct {
|
|
Status string `json:"status"`
|
|
UpstreamStatus int `json:"upstream_status,omitempty"`
|
|
}
|
|
|
|
// ScoreContent scores text for AI patterns via POST /v1/score/content.
|
|
func (c *Client) ScoreContent(ctx context.Context, req ScoreContentRequest) (ScoreResult, error) {
|
|
const op = "agentic.Client.ScoreContent"
|
|
|
|
if req.Text == "" {
|
|
return nil, log.E(op, "text is required", nil)
|
|
}
|
|
|
|
data, err := json.Marshal(req)
|
|
if err != nil {
|
|
return nil, log.E(op, "failed to marshal request", err)
|
|
}
|
|
|
|
endpoint := c.BaseURL + "/v1/score/content"
|
|
|
|
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, bytes.NewReader(data))
|
|
if err != nil {
|
|
return nil, log.E(op, "failed to create request", err)
|
|
}
|
|
|
|
c.setHeaders(httpReq)
|
|
httpReq.Header.Set("Content-Type", "application/json")
|
|
|
|
resp, err := c.HTTPClient.Do(httpReq)
|
|
if err != nil {
|
|
return nil, log.E(op, "request failed", err)
|
|
}
|
|
defer func() { _ = resp.Body.Close() }()
|
|
|
|
if err := c.checkResponse(resp); err != nil {
|
|
return nil, log.E(op, "API error", err)
|
|
}
|
|
|
|
var result ScoreResult
|
|
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
|
return nil, log.E(op, "failed to decode response", err)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// ScoreImprint performs linguistic imprint analysis via POST /v1/score/imprint.
|
|
func (c *Client) ScoreImprint(ctx context.Context, req ScoreImprintRequest) (ScoreResult, error) {
|
|
const op = "agentic.Client.ScoreImprint"
|
|
|
|
if req.Text == "" {
|
|
return nil, log.E(op, "text is required", nil)
|
|
}
|
|
|
|
data, err := json.Marshal(req)
|
|
if err != nil {
|
|
return nil, log.E(op, "failed to marshal request", err)
|
|
}
|
|
|
|
endpoint := c.BaseURL + "/v1/score/imprint"
|
|
|
|
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, bytes.NewReader(data))
|
|
if err != nil {
|
|
return nil, log.E(op, "failed to create request", err)
|
|
}
|
|
|
|
c.setHeaders(httpReq)
|
|
httpReq.Header.Set("Content-Type", "application/json")
|
|
|
|
resp, err := c.HTTPClient.Do(httpReq)
|
|
if err != nil {
|
|
return nil, log.E(op, "request failed", err)
|
|
}
|
|
defer func() { _ = resp.Body.Close() }()
|
|
|
|
if err := c.checkResponse(resp); err != nil {
|
|
return nil, log.E(op, "API error", err)
|
|
}
|
|
|
|
var result ScoreResult
|
|
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
|
return nil, log.E(op, "failed to decode response", err)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// ScoreHealth checks the scoring engine health via GET /v1/score/health.
|
|
// This endpoint does not require authentication.
|
|
func (c *Client) ScoreHealth(ctx context.Context) (*ScoreHealthResponse, error) {
|
|
const op = "agentic.Client.ScoreHealth"
|
|
|
|
endpoint := c.BaseURL + "/v1/score/health"
|
|
|
|
httpReq, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)
|
|
if err != nil {
|
|
return nil, log.E(op, "failed to create request", err)
|
|
}
|
|
|
|
// Health endpoint is unauthenticated but we still set headers for consistency.
|
|
httpReq.Header.Set("Accept", "application/json")
|
|
httpReq.Header.Set("User-Agent", "core-agentic-client/1.0")
|
|
|
|
resp, err := c.HTTPClient.Do(httpReq)
|
|
if err != nil {
|
|
return nil, log.E(op, "request failed", err)
|
|
}
|
|
defer func() { _ = resp.Body.Close() }()
|
|
|
|
if err := c.checkResponse(resp); err != nil {
|
|
return nil, log.E(op, "API error", err)
|
|
}
|
|
|
|
var result ScoreHealthResponse
|
|
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
|
return nil, log.E(op, "failed to decode response", err)
|
|
}
|
|
|
|
return &result, nil
|
|
}
|