agent/pkg/lifecycle/score.go
Snider e90a84eaa0 feat: merge go-agent + go-agentic + php-devops into unified agent repo
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>
2026-03-06 15:23:00 +00:00

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
}