Skip to content

Commit 5b031fa

Browse files
committed
feat: handle market challenges natively without LLM
Add Type/MarketEndpoint/AnswerFormat fields to Challenge struct. When challenge.Type == "market", bypass LLM and HTTP GET the market_endpoint to fetch the live count (total field), returning the integer as the answer directly. This covers the new 20% market challenge rate introduced in the inscribe-worker without burning LLM calls on deterministic answers.
1 parent 3f70625 commit 5b031fa

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

internal/api/types.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ type Challenge struct {
9898
ID string `json:"id"`
9999
Prompt string `json:"prompt"`
100100
ExpiresIn int `json:"expires_in"`
101+
102+
// Market challenge fields (Type == "market").
103+
// The CLI should HTTP GET MarketEndpoint (no auth) and return the count as the answer.
104+
Type string `json:"type,omitempty"` // "market" | "" (language challenge)
105+
MarketEndpoint string `json:"market_endpoint,omitempty"` // read-only API URL
106+
AnswerFormat string `json:"answer_format,omitempty"` // "integer"
101107
}
102108

103109
// GenesisNFT represents an agent's won NFT.

internal/miner/loop.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@ package miner
22

33
import (
44
"context"
5+
"encoding/json"
56
"errors"
67
"fmt"
8+
"io"
79
"log/slog"
810
"math/rand"
11+
"net/http"
912
"strconv"
1013
"strings"
1114
"time"
@@ -485,7 +488,45 @@ func (m *Miner) mineOnce(ctx context.Context) (*api.InscribeResponse, error) {
485488
return resp, nil
486489
}
487490

491+
func (m *Miner) answerMarketChallenge(ctx context.Context, challenge *api.Challenge) (string, error) {
492+
slog.Info("Market challenge: fetching live data", "endpoint", challenge.MarketEndpoint)
493+
fmt.Printf(i18n.Tr(" [Market] Fetching: %s\n", " [市场] 获取数据: %s\n"), challenge.MarketEndpoint)
494+
495+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, challenge.MarketEndpoint, nil)
496+
if err != nil {
497+
return "", fmt.Errorf("market challenge: build request: %w", err)
498+
}
499+
500+
resp, err := http.DefaultClient.Do(req)
501+
if err != nil {
502+
return "", fmt.Errorf("market challenge: http get: %w", err)
503+
}
504+
defer resp.Body.Close()
505+
506+
body, err := io.ReadAll(resp.Body)
507+
if err != nil {
508+
return "", fmt.Errorf("market challenge: read body: %w", err)
509+
}
510+
511+
var result struct {
512+
Total int `json:"total"`
513+
}
514+
if err := json.Unmarshal(body, &result); err != nil {
515+
return "", fmt.Errorf("market challenge: parse response: %w", err)
516+
}
517+
518+
answer := strconv.Itoa(result.Total)
519+
slog.Info("Market challenge answered", "total", result.Total)
520+
fmt.Printf(i18n.Tr(" [Market] Answer: %s\n", " [市场] 答案: %s\n"), answer)
521+
return answer, nil
522+
}
523+
488524
func (m *Miner) answerChallenge(ctx context.Context, challenge *api.Challenge) (string, error) {
525+
// Market challenges bypass LLM — fetch live data from the provided endpoint.
526+
if challenge.Type == "market" && challenge.MarketEndpoint != "" {
527+
return m.answerMarketChallenge(ctx, challenge)
528+
}
529+
489530
DisplayChallenge(challenge.Prompt)
490531
display := challenge.Prompt
491532
if len(display) > 80 {

0 commit comments

Comments
 (0)