internal/httpapi/phase3.go (2627 lines, 12+ resource domains) split into 15 per-resource files: - actuator.go: SSH execution machinery (initSSH, sshExec, resolveRunTarget, executeApprovedAction, jsonErr, gatewayPreflightPassed, resolveTemplate) - checks.go, classifications.go, executions.go, approvals.go, patterns.go, skills.go, approval_rules.go, autonomy.go, risk_classes.go, relationships.go, entity_types.go, metrics.go, agent_activity.go, helpers.go — one file per resource domain, each with its own imports. internal/mcp/server.go: newServer (708 lines, 33 inline tool registrations) refactored to a registry pattern: - internal/mcp/tools.go (new): toolReg struct + allTools() returning all 33 tool definitions. Handler logic moved verbatim — no changes to tool names, descriptions, schemas, or behavior. - server.go: newServer is now 9 lines (iterate registry, AddTool each). -699 lines. No function logic, names, or signatures changed. go vet, build, and all tests pass (httpapi, mcp, db, policy).
91 lines
2.5 KiB
Go
91 lines
2.5 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/dtoro/oikos/internal/httpapi/gen"
|
|
)
|
|
|
|
// ─── Agent Activity (stub) ─────────────────────────────────────────────
|
|
|
|
func (s *Server) QueryAgentActivity(ctx context.Context, request gen.QueryAgentActivityRequestObject) (gen.QueryAgentActivityResponseObject, error) {
|
|
limit := clampLimit(request.Params.Limit)
|
|
from := time.Now().Add(-24 * time.Hour)
|
|
if request.Params.From != nil {
|
|
from = *request.Params.From
|
|
}
|
|
to := time.Now()
|
|
if request.Params.To != nil {
|
|
to = *request.Params.To
|
|
}
|
|
|
|
var agentID *string
|
|
if request.Params.AgentId != nil {
|
|
a := *request.Params.AgentId
|
|
agentID = &a
|
|
}
|
|
var activityType *string
|
|
if request.Params.ActivityType != nil {
|
|
a := string(*request.Params.ActivityType)
|
|
activityType = &a
|
|
}
|
|
var entityID *string
|
|
if request.Params.EntityId != nil {
|
|
a := *request.Params.EntityId
|
|
entityID = &a
|
|
}
|
|
var cursorID *int
|
|
if request.Params.Cursor != nil && *request.Params.Cursor != "" {
|
|
if id, err := parseIntOrZero(*request.Params.Cursor); err == nil && id > 0 {
|
|
cursorID = &id
|
|
}
|
|
}
|
|
|
|
rows, err := s.pool.Query(ctx, `
|
|
SELECT id, ts, agent_id::text, session_id, activity_type, tool_name,
|
|
entity_id::text, input_summary, output_summary,
|
|
duration_ms, token_count, success, correlation_id
|
|
FROM agent_activity
|
|
WHERE ts >= $1 AND ts <= $2
|
|
AND ($3::text IS NULL OR agent_id::text = $3)
|
|
AND ($4::text IS NULL OR activity_type = $4)
|
|
AND ($5::text IS NULL OR entity_id::text = $5)
|
|
AND ($6::bigint IS NULL OR id < $6::bigint)
|
|
ORDER BY id DESC
|
|
LIMIT $7`,
|
|
from, to, agentID, activityType, entityID, cursorID, limit+1)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
items := []gen.AgentActivity{}
|
|
for rows.Next() {
|
|
var a gen.AgentActivity
|
|
if err := rows.Scan(&a.Id, &a.Ts, &a.AgentId, &a.SessionId,
|
|
&a.ActivityType, &a.ToolName, &a.EntityId,
|
|
&a.InputSummary, &a.OutputSummary,
|
|
&a.DurationMs, &a.TokenCount, &a.Success,
|
|
&a.CorrelationId); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, a)
|
|
}
|
|
if rows.Err() != nil {
|
|
return nil, rows.Err()
|
|
}
|
|
|
|
var next *string
|
|
if len(items) > limit {
|
|
items = items[:limit]
|
|
lastID := fmt.Sprintf("%d", items[len(items)-1].Id)
|
|
next = &lastID
|
|
}
|
|
if items == nil {
|
|
items = []gen.AgentActivity{}
|
|
}
|
|
return gen.QueryAgentActivity200JSONResponse{Items: items, NextCursor: next}, nil
|
|
}
|