package api import ( "fmt" "io" "net/http" "time" "github.com/claudia/docs-cli/pkg/types" ) // ReasoningClient handles reasoning API calls type ReasoningClient struct { client *Client } // NewReasoningClient creates a new reasoning client func NewReasoningClient(c *Client) *ReasoningClient { return &ReasoningClient{client: c} } // Save saves reasoning for a document func (r *ReasoningClient) Save(docID string, req types.SaveReasoningRequest) (*types.Reasoning, error) { path := "/documents/" + docID + "/reasoning" resp, err := r.client.doRequest(http.MethodPut, path, req) if err != nil { return nil, err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("failed to read response: %w", err) } if resp.StatusCode != http.StatusOK { return nil, handleError(resp, body) } var reasoningResp types.Response if err := decodeJSON(body, &reasoningResp); err != nil { return nil, err } reasoning, ok := reasoningResp.Data.(map[string]interface{}) if !ok { return nil, fmt.Errorf("unexpected response format") } return mapToReasoning(reasoning), nil } // Get gets reasoning for a document func (r *ReasoningClient) Get(docID string) (*types.Reasoning, error) { path := "/documents/" + docID + "/reasoning" resp, err := r.client.doRequest(http.MethodGet, path, nil) if err != nil { return nil, err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("failed to read response: %w", err) } if resp.StatusCode != http.StatusOK { return nil, handleError(resp, body) } var reasoningResp types.Response if err := decodeJSON(body, &reasoningResp); err != nil { return nil, err } reasoning, ok := reasoningResp.Data.(map[string]interface{}) if !ok { return nil, fmt.Errorf("unexpected response format") } return mapToReasoning(reasoning), nil } func mapToReasoning(m map[string]interface{}) *types.Reasoning { reasoning := &types.Reasoning{} if v, ok := m["doc_id"].(string); ok { reasoning.DocID = v } if v, ok := m["type"].(string); ok { reasoning.Type = v } if v, ok := m["confidence"].(float64); ok { reasoning.Confidence = v } if v, ok := m["model"].(string); ok { reasoning.Model = v } if v, ok := m["created_at"].(string); ok { reasoning.CreatedAt, _ = time.Parse(time.RFC3339, v) } if steps, ok := m["steps"].([]interface{}); ok { for _, step := range steps { if s, ok := step.(map[string]interface{}); ok { reasoningStep := types.ReasoningStep{} if sid, ok := s["step_id"].(string); ok { reasoningStep.StepID = sid } if thought, ok := s["thought"].(string); ok { reasoningStep.Thought = thought } if conclusion, ok := s["conclusion"].(string); ok { reasoningStep.Conclusion = conclusion } if action, ok := s["action"].(string); ok { reasoningStep.Action = action } reasoning.Steps = append(reasoning.Steps, reasoningStep) } } } return reasoning }