mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-07-10 00:14:38 +00:00
Manifest-backed MCP tools, prompts, and resources with surface affordance contracts; agent capability manifest and governance projection; API contract tests and capability route projection; operations-loop and intelligence-funnel telemetry; release-control subsystem documentation, registry, and tooling; licensing and configuration.
131 lines
4 KiB
Go
131 lines
4 KiB
Go
package agentcapabilities
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
ErrCodeFSMBlocked = "FSM_BLOCKED"
|
|
ErrCodeStrictResolution = "STRICT_RESOLUTION"
|
|
ErrCodeRoutingMismatch = "ROUTING_MISMATCH"
|
|
ErrCodeExecutionContextUnavailable = "EXECUTION_CONTEXT_UNAVAILABLE"
|
|
ErrCodeNotFound = "NOT_FOUND"
|
|
ErrCodeActionNotAllowed = "ACTION_NOT_ALLOWED"
|
|
ErrCodePolicyBlocked = "POLICY_BLOCKED"
|
|
ErrCodeApprovalRequired = "APPROVAL_REQUIRED"
|
|
ErrCodeInvalidInput = "INVALID_INPUT"
|
|
ErrCodeExecutionFailed = "EXECUTION_FAILED"
|
|
ErrCodeNoAgent = "NO_AGENT"
|
|
)
|
|
|
|
// ToolResponse is the structured tool-result envelope used when a tool needs
|
|
// machine-readable success/failure fields inside the shared text result
|
|
// wrapper. It is shared so Assistant tools and agent-facing adapters branch on
|
|
// the same blocked/failed/retryable vocabulary.
|
|
type ToolResponse struct {
|
|
OK bool `json:"ok"`
|
|
Data any `json:"data,omitempty"`
|
|
Error *ToolError `json:"error,omitempty"`
|
|
Meta map[string]any `json:"meta,omitempty"`
|
|
}
|
|
|
|
// ToolError provides the structured failure shape for ToolResponse.
|
|
type ToolError struct {
|
|
Code string `json:"code"`
|
|
Message string `json:"message"`
|
|
Blocked bool `json:"blocked,omitempty"`
|
|
Failed bool `json:"failed,omitempty"`
|
|
Retryable bool `json:"retryable,omitempty"`
|
|
Details map[string]any `json:"details,omitempty"`
|
|
}
|
|
|
|
// NewToolBlockedError creates a policy or validation blocked tool response.
|
|
func NewToolBlockedError(code, message string, details map[string]any) ToolResponse {
|
|
return ToolResponse{
|
|
OK: false,
|
|
Error: &ToolError{
|
|
Code: code,
|
|
Message: message,
|
|
Blocked: true,
|
|
Details: details,
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewToolResponseResult wraps a structured ToolResponse in the shared tool
|
|
// result envelope while preserving failure state through isError.
|
|
func NewToolResponseResult(resp ToolResponse) ToolResult {
|
|
return NewToolJSONResultWithIsError(resp, !resp.OK)
|
|
}
|
|
|
|
func toolResultJSONObject(resultText string) (map[string]any, bool) {
|
|
if resultText == "" {
|
|
return nil, false
|
|
}
|
|
jsonStart := strings.Index(resultText, "{")
|
|
if jsonStart == -1 {
|
|
return nil, false
|
|
}
|
|
|
|
var obj map[string]any
|
|
if err := json.Unmarshal([]byte(resultText[jsonStart:]), &obj); err != nil {
|
|
return nil, false
|
|
}
|
|
return obj, true
|
|
}
|
|
|
|
// ToolResultErrorCode extracts the shared ToolResponse error code from a tool
|
|
// result text. It also accepts the legacy top-level error_code shape so old
|
|
// persisted transcripts and compatibility paths branch through the same helper.
|
|
func ToolResultErrorCode(resultText string) (string, bool) {
|
|
obj, ok := toolResultJSONObject(resultText)
|
|
if !ok {
|
|
return "", false
|
|
}
|
|
if errorAny, ok := obj["error"]; ok {
|
|
if errorMap, ok := errorAny.(map[string]any); ok {
|
|
if code, ok := errorMap["code"].(string); ok && strings.TrimSpace(code) != "" {
|
|
return code, true
|
|
}
|
|
}
|
|
}
|
|
if code, ok := obj["error_code"].(string); ok && strings.TrimSpace(code) != "" {
|
|
return code, true
|
|
}
|
|
return "", false
|
|
}
|
|
|
|
// ToolResultHasErrorCode reports whether a tool result text carries the given
|
|
// shared ToolResponse error code.
|
|
func ToolResultHasErrorCode(resultText, code string) bool {
|
|
got, ok := ToolResultErrorCode(resultText)
|
|
return ok && got == code
|
|
}
|
|
|
|
// ToolResultHasVerificationOK checks whether a tool result text includes
|
|
// structured verification evidence indicating a mutation was confirmed.
|
|
//
|
|
// Expected shape, possibly after leading human-readable text:
|
|
//
|
|
// { "verification": { "ok": true, ... } }
|
|
func ToolResultHasVerificationOK(resultText string) bool {
|
|
obj, ok := toolResultJSONObject(resultText)
|
|
if !ok {
|
|
return false
|
|
}
|
|
vAny, ok := obj["verification"]
|
|
if !ok {
|
|
return false
|
|
}
|
|
vMap, ok := vAny.(map[string]any)
|
|
if !ok {
|
|
return false
|
|
}
|
|
okAny, ok := vMap["ok"]
|
|
if !ok {
|
|
return false
|
|
}
|
|
okBool, ok := okAny.(bool)
|
|
return ok && okBool
|
|
}
|