new-agent
skillCreate a new underwriting agent (assets, credit, collateral) following established patterns. Use when implementing new agents, extending the system with new document analysis capabilities, or understanding how agents work.
apm::install
apm install @majiayu000/new-agentapm::skill.md
---
name: new-agent
description: Create a new underwriting agent (assets, credit, collateral) following established patterns. Use when implementing new agents, extending the system with new document analysis capabilities, or understanding how agents work.
---
# Create New Underwriting Agent
## Purpose
Create new agents for assets, credit, or collateral analysis following the income agent pattern.
## Agent Interface
All agents must implement this interface from `internal/agent/agent.go`:
```go
type Agent interface {
Type() AgentType
Name() string
RequiredDocuments() []model.DocumentType
OptionalDocuments() []model.DocumentType
Dependencies() []AgentType
Analyze(ctx context.Context, input *AnalysisInput) (*model.AnalysisResult, error)
CanProceed(docs []*model.Document) (bool, []model.DocumentType)
}
```
## Agent Types
```go
const (
AgentTypeIncome AgentType = "income"
AgentTypeAssets AgentType = "assets"
AgentTypeCredit AgentType = "credit"
AgentTypeCollateral AgentType = "collateral"
)
```
## Step-by-Step Guide
### 1. Create Directory Structure
```bash
mkdir -p internal/agent/<agentname>
```
### 2. Create Agent File
Use this template based on `internal/agent/income/income.go`:
```go
package <agentname>
import (
"context"
"encoding/json"
"fmt"
"strings"
"time"
"github.com/nimag/fast/internal/agent"
"github.com/nimag/fast/internal/gemini"
"github.com/nimag/fast/internal/guidelines"
"github.com/nimag/fast/internal/model"
)
type Agent struct {
gemini *gemini.Client
guidelines string
}
type Config struct {
GuidelinesPath string
}
func New(geminiClient *gemini.Client) *Agent {
return &Agent{gemini: geminiClient}
}
func NewWithConfig(geminiClient *gemini.Client, cfg Config) *Agent {
a := &Agent{gemini: geminiClient}
if cfg.GuidelinesPath != "" {
loader := guidelines.NewLoader(cfg.GuidelinesPath)
// Load appropriate section: "assets", "credit", or "collateral"
if content, err := loader.LoadSection("<section>"); err == nil {
a.guidelines = content
}
}
return a
}
func (a *Agent) Type() agent.AgentType {
return agent.AgentType<Name>
}
func (a *Agent) Name() string {
return "<Name> Verification Agent"
}
func (a *Agent) RequiredDocuments() []model.DocumentType {
return []model.DocumentType{
// Add required document types
}
}
func (a *Agent) OptionalDocuments() []model.DocumentType {
return []model.DocumentType{
// Add optional document types
}
}
func (a *Agent) Dependencies() []agent.AgentType {
return nil // Or list dependent agents
}
func (a *Agent) CanProceed(docs []*model.Document) (bool, []model.DocumentType) {
required := a.RequiredDocuments()
// Check if required docs are present
// Return (true, nil) if can proceed
// Return (false, missingTypes) if cannot
}
func (a *Agent) Analyze(ctx context.Context, input *agent.AnalysisInput) (*model.AnalysisResult, error) {
// 1. Filter documents for this agent
// 2. Build prompts
// 3. Call Gemini
// 4. Parse response
// 5. Return AnalysisResult
}
```
### 3. Document Types by Agent
**Assets Agent:**
```go
Required: DocTypeBankStatement
Optional: DocTypeAssetStatement, DocTypeRetirementStmt, DocTypeGiftLetter
```
**Credit Agent:**
```go
Required: DocTypeCreditReport
Optional: DocTypeDebtPayoff
```
**Collateral Agent:**
```go
Required: DocTypeAppraisal
Optional: DocTypePurchaseContract, DocTypeTitleReport, DocTypePropertyInsurance
```
### 4. Guidelines Section Mapping
```go
// Load the correct section for your agent
loader.LoadSection("assets") // For assets agent
loader.LoadSection("credit") // For credit agent
loader.LoadSection("collateral") // For collateral agent
```
### 5. Streaming Output Format
For streaming analysis with real-time progress display, prompts should output markers that `StreamFormatter` detects. See the **streaming-output** skill for the full specification.
Key markers:
```
**📋 GUIDELINE: [Section ID] - [Title]**
Status: ✅ COMPLIANT | ⚠️ ISSUE | ❌ NON-COMPLIANT
**🔍 CROSS-CHECK: [Doc1] vs [Doc2]**
Result: MATCH | MISMATCH
**🧮 INCOME CALCULATION**
Base annual salary: $X,XXX.XX
Total qualifying monthly income: $X,XXX.XX
**✅ FINAL DETERMINATION**
Status: APPROVED | DENIED | NEEDS REVIEW
```
### 6. System Prompt Pattern
```go
func (a *Agent) buildSystemPrompt() string {
// Load guidelines - they contain the analysis instructions
// Don't duplicate guideline content in the prompt
if a.guidelines != "" {
return "## Fannie Mae Guidelines\n\n" + a.guidelines
}
return ""
}
```
### 7. Response Parsing
Request JSON output and parse into `model.AnalysisResult`:
```go
type analysisResponse struct {
Status string `json:"status"`
Confidence float64 `json:"confidence"`
Summary string `json:"summary"`
Findings []finding `json:"findings"`
Risks []risk `json:"risks"`
MissingDocuments []string `json:"missing_documents"`
}
```
### 8. Register in Main
Update `cmd/underwriter/main.go`:
```go
import "<agentname>" // Add import
// Create agent
newAgent := <agentname>.NewWithConfig(geminiClient, <agentname>.Config{
GuidelinesPath: *guidelinesDir,
})
// Add to agents slice
agents := []agent.Agent{incomeAgent, newAgent}
```
## Reference Implementation
Study `internal/agent/income/income.go` for:
- Complete Analyze() implementation
- Prompt building patterns
- JSON response parsing
- Error handling
- Document filtering
## Related Files
- `internal/agent/agent.go` - Interface definition
- `internal/agent/income/income.go` - Reference implementation
- `internal/model/document.go` - Document types
- `internal/model/analysis.go` - Result structures
- `internal/guidelines/loader.go` - Guideline loading
- `configs/guidelines/` - Guideline files by section