# ADK-Go Integration Pattern

## Summary

Tool definitions and callback patterns for Google ADK-Go agents consuming Episteme. Covers query, assert, constraint check, and trace operations with proper struct tags and callback signatures.

## Core Mechanism

ADK-Go agents interact with Episteme through:

1. **Tools** - Structured operations (query, assert, trace) defined as Go structs
2. **Callbacks** - Hooks for pre-flight checks and audit logging
3. **State** - Session state for agent-to-agent communication

## Tool Definition Pattern

All Episteme tools follow this structure:

```go
import (
    "google.golang.org/adk/tool"
    "google.golang.org/adk/tool/functiontool"
)

type [Operation]Input struct {
    // Required fields (no omitempty)
    Subject   string `json:"subject" jsonschema:"Entity to query (e.g., auth/jwt)"`
    Predicate string `json:"predicate" jsonschema:"Relation to query (e.g., signing_algorithm)"`

    // Optional fields (with omitempty)
    Lens      string `json:"lens,omitempty" jsonschema:"Resolution: consensus, authority, recency, constraints"`
}

type [Operation]Output struct {
    Value      interface{} `json:"value"`
    Confidence float32     `json:"confidence"`
    QueryID    string      `json:"query_id"`  // CRITICAL: for audit trail
    Error      string      `json:"error,omitempty"`
}

func [operation](ctx tool.Context, input [Operation]Input) [Operation]Output {
    // 1. Call Episteme API
    // 2. Return structured result with QueryID
}

// Register with functiontool.New()
tool, err := functiontool.New(
    functiontool.Config{
        Name:        "episteme_query",
        Description: "Query Episteme knowledge graph",
    },
    queryEpisteme,
)
```

## Standard Tools

### Query Tool

```go
type QueryInput struct {
    Subject       string  `json:"subject" jsonschema:"Entity to query (e.g., auth/jwt)"`
    Predicate     string  `json:"predicate" jsonschema:"Relation to query (e.g., signing_algorithm)"`
    Lens          string  `json:"lens,omitempty" jsonschema:"Resolution: consensus, authority, recency, constraints"`
    Lifecycle     string  `json:"lifecycle,omitempty" jsonschema:"Filter: proposed, approved, deprecated"`
    MinConfidence float32 `json:"min_confidence,omitempty" jsonschema:"Minimum confidence threshold (0.0-1.0)"`
    AsOf          string  `json:"as_of,omitempty" jsonschema:"Time-travel: ISO8601 timestamp"`
}

type QueryOutput struct {
    Value      interface{} `json:"value"`
    Confidence float32     `json:"confidence"`
    Lifecycle  string      `json:"lifecycle"`
    Sources    []Source    `json:"sources"`
    QueryID    string      `json:"query_id"`
}
```

### Assert Tool

```go
type AssertInput struct {
    Subject    string      `json:"subject" jsonschema:"Entity being described"`
    Predicate  string      `json:"predicate" jsonschema:"Relation being asserted"`
    Object     interface{} `json:"object" jsonschema:"Value being claimed"`
    SourceHash string      `json:"source_hash" jsonschema:"BLAKE3 hash of evidence"`
    Confidence float32     `json:"confidence" jsonschema:"Certainty level (0.0-1.0)"`
    Lifecycle  string      `json:"lifecycle,omitempty" jsonschema:"proposed, under_review, approved"`
    ParentHash string      `json:"parent_hash,omitempty" jsonschema:"Hash of assertion being updated"`
    Meta       *AssertMeta `json:"meta,omitempty" jsonschema:"Additional metadata"`
}

type AssertMeta struct {
    ForbiddenAlternative string `json:"forbidden_alternative,omitempty"`
    Reason               string `json:"reason,omitempty"`
}

type AssertOutput struct {
    Hash    string `json:"hash"`
    Success bool   `json:"success"`
    Error   string `json:"error,omitempty"`
}
```

### Constraint Check Tool

```go
type ConstraintCheckInput struct {
    Context string `json:"context" jsonschema:"Domain context (e.g., python_http, auth_jwt)"`
}

type ConstraintCheckOutput struct {
    Constraints []Constraint `json:"constraints"`
}

type Constraint struct {
    Subject   string `json:"subject"`
    MustUse   string `json:"must_use,omitempty"`
    Forbidden string `json:"forbidden,omitempty"`
    Reason    string `json:"reason"`
}
```

### Trace Tool (SRE)

```go
type TraceInput struct {
    AgentID string `json:"agent_id" jsonschema:"Agent to trace"`
    From    string `json:"from" jsonschema:"Start time (ISO8601 or relative like -6h)"`
    To      string `json:"to,omitempty" jsonschema:"End time (default: now)"`
    Subject string `json:"subject,omitempty" jsonschema:"Filter by subject pattern (e.g., auth/*)"`
}

type TraceOutput struct {
    Queries []QueryTrace `json:"queries"`
}

type QueryTrace struct {
    QueryID      string   `json:"query_id"`
    Timestamp    string   `json:"timestamp"`
    Subject      string   `json:"subject"`
    Predicate    string   `json:"predicate"`
    Lens         string   `json:"lens"`
    Result       string   `json:"result"`
    Confidence   float32  `json:"confidence"`
    Contributing []string `json:"contributing_assertions"`
}
```

## Callback Integration

### BeforeToolCallback - Constraint Pre-flight

Critical for preventing repeat mistakes:

```go
agent, err := llmagent.New(llmagent.Config{
    Name:  "implementation_agent",
    Model: model,
    Tools: []tool.Tool{queryTool, assertTool},

    BeforeToolCallback: func(ctx agent.CallbackContext, call *tool.Call) (*tool.Call, error) {
        // Check constraints before any tool that could use wrong patterns
        if needsConstraintCheck(call) {
            constraints := checkConstraints(ctx, extractContext(call))
            for _, c := range constraints {
                if violates(call, c) {
                    return nil, fmt.Errorf("blocked: %s is forbidden - %s",
                        c.Forbidden, c.Reason)
                }
            }
        }
        return call, nil
    },
})
```

### AfterModelCallback - Audit Trail

Log agent decisions for debugging:

```go
AfterModelCallback: func(ctx agent.CallbackContext, resp *model.LLMResponse) (*model.LLMResponse, error) {
    // Log what the agent decided for future tracing
    decision := extractDecision(resp)
    logToEpisteme(ctx, AuditEntry{
        AgentID:   ctx.Agent().Name(),
        Timestamp: time.Now(),
        Decision:  decision,
        Context:   ctx.Session().State(),
    })
    return resp, nil
},
```

### AfterToolCallback - Error Learning

Trigger Gardener when tools fail:

```go
AfterToolCallback: func(ctx agent.CallbackContext, call *tool.Call, result *tool.Result) (*tool.Result, error) {
    if result.Error != nil {
        // Notify Gardener of the failure for TrustRank back-propagation
        notifyGardener(ctx, GardenerEvent{
            AgentID:     ctx.Agent().Name(),
            ToolCall:    call,
            Error:       result.Error,
            QueryID:     extractQueryID(call),
        })
    }
    return result, nil
},
```

## Agent-Specific Patterns

### Lead Orchestrator

Fast queries with confidence thresholds:

```go
result := queryEpisteme(ctx, QueryInput{
    Subject:       "auth/jwt",
    Predicate:     "signing_algorithm",
    Lens:          "authority",
    MinConfidence: 0.8,
})
if result.Confidence < 0.8 {
    // Escalate to human or research agent
    return escalate(ctx, result)
}
```

### Implementation Agent

Approved patterns only:

```go
result := queryEpisteme(ctx, QueryInput{
    Subject:   "auth/jwt",
    Predicate: "signing_algorithm",
    Lens:      "authority",
    Lifecycle: "approved",  // CRITICAL: never use proposed patterns
})
```

### Research Agent

Store with uncertainty and contradictions:

```go
assertKnowledge(ctx, AssertInput{
    Subject:    "jwt_rotation",
    Predicate:  "best_practice",
    Object:     "rotate_daily",
    SourceHash: hashURL(sourceURL),
    Confidence: 0.7,  // Express uncertainty
    Lifecycle:  "proposed",
})

// Store contradicting information - don't flatten
assertKnowledge(ctx, AssertInput{
    Subject:    "jwt_rotation",
    Predicate:  "best_practice",
    Object:     "rotate_weekly",
    SourceHash: hashURL(differentSourceURL),
    Confidence: 0.6,
    Lifecycle:  "proposed",
})
```

### Human Supervisor

Time-travel and corrections:

```go
// What was believed during the incident?
result := queryEpisteme(ctx, QueryInput{
    Subject:   "auth/jwt",
    Predicate: "signing_algorithm",
    AsOf:      "2024-01-15T21:00:00Z",
})

// Correct the record
supersede(ctx, SupersedeInput{
    Hash:   badAssertionHash,
    Reason: "Proposal treated as approved - was never reviewed",
    Type:   "Invalidate",
})
```

### On-Call SRE

Trace agent decisions:

```go
traces := traceAgentQueries(ctx, TraceInput{
    AgentID: "deployment-agent",
    From:    "-6h",
    Subject: "auth/*",
})

for _, t := range traces.Queries {
    fmt.Printf("[%s] %s/%s via %s -> %s (%.2f)\n",
        t.Timestamp, t.Subject, t.Predicate,
        t.Lens, t.Result, t.Confidence)
    fmt.Printf("  Contributing: %v\n", t.Contributing)
}
```

## State vs Episteme

| Use | Mechanism |
|-----|-----------|
| Agent-to-agent handoff (same session) | Session State + OutputKey |
| Persistent organizational knowledge | Episteme Assert |
| What was decided in this conversation | Session State |
| What should all agents know forever | Episteme Assert |
| Temporary working data | `temp:` prefixed state keys |
| Audit trail | Episteme QueryAudit |

## Related

- [services/assertion.md](../services/assertion.md) - Core assertion structure
- [services/lens.md](../services/lens.md) - Lens resolution strategies
- [services/lifecycle.md](../services/lifecycle.md) - Lifecycle stage filtering
- [features/gardener.md](../features/gardener.md) - Error back-propagation
- [features/query-audit.md](../features/query-audit.md) - Trace and debug
