| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- package tools
- import (
- "context"
- "fmt"
- "strings"
- "github.com/vektah/gqlparser/v2/ast"
- )
- // CallToolResult represents the result of a tool call
- type CallToolResult struct {
- Content []ContentBlock `json:"content"`
- IsError bool `json:"isError,omitempty"`
- }
- // ContentBlock represents a content block in a tool result
- type ContentBlock struct {
- Type string `json:"type"`
- Text string `json:"text"`
- }
- // Introspect returns GraphQL schema information
- func Introspect(ctx context.Context, schema *ast.Schema, args map[string]interface{}) (CallToolResult, error) {
- typeName, _ := args["typeName"].(string)
- var result strings.Builder
- if typeName != "" {
- // Introspect specific type
- result.WriteString(introspectType(schema, typeName))
- } else {
- // Full schema overview
- result.WriteString("# ARP GraphQL Schema Overview\n\n")
- // Query type
- result.WriteString("## Query Type\n")
- result.WriteString(introspectType(schema, "Query"))
- result.WriteString("\n")
- // Mutation type
- result.WriteString("## Mutation Type\n")
- result.WriteString(introspectType(schema, "Mutation"))
- result.WriteString("\n")
- // Subscription type
- result.WriteString("## Subscription Type\n")
- result.WriteString(introspectType(schema, "Subscription"))
- result.WriteString("\n")
- // Object types
- result.WriteString("## Object Types\n")
- for _, t := range schema.Types {
- if t.Kind == ast.Object && !strings.HasPrefix(t.Name, "__") && t.Name != "Query" && t.Name != "Mutation" && t.Name != "Subscription" {
- result.WriteString(fmt.Sprintf("### %s\n", t.Name))
- result.WriteString(introspectType(schema, t.Name))
- result.WriteString("\n")
- }
- }
- // Input types
- result.WriteString("## Input Types\n")
- for _, t := range schema.Types {
- if t.Kind == ast.InputObject && !strings.HasPrefix(t.Name, "__") {
- result.WriteString(fmt.Sprintf("### %s\n", t.Name))
- result.WriteString(introspectInputType(t))
- result.WriteString("\n")
- }
- }
- }
- return CallToolResult{
- Content: []ContentBlock{
- {Type: "text", Text: result.String()},
- },
- }, nil
- }
- func introspectType(schema *ast.Schema, typeName string) string {
- t := schema.Types[typeName]
- if t == nil {
- return fmt.Sprintf("Type '%s' not found\n", typeName)
- }
- var result strings.Builder
- switch t.Kind {
- case ast.Object:
- result.WriteString(fmt.Sprintf("Type: %s (Object)\n", t.Name))
- if t.Description != "" {
- result.WriteString(fmt.Sprintf("Description: %s\n", t.Description))
- }
- result.WriteString("\nFields:\n")
- for _, field := range t.Fields {
- result.WriteString(formatField(field))
- }
- case ast.Interface:
- result.WriteString(fmt.Sprintf("Type: %s (Interface)\n", t.Name))
- if t.Description != "" {
- result.WriteString(fmt.Sprintf("Description: %s\n", t.Description))
- }
- result.WriteString("\nFields:\n")
- for _, field := range t.Fields {
- result.WriteString(formatField(field))
- }
- case ast.Union:
- result.WriteString(fmt.Sprintf("Type: %s (Union)\n", t.Name))
- result.WriteString("Members:\n")
- for _, member := range t.Types {
- result.WriteString(fmt.Sprintf(" - %s\n", member))
- }
- case ast.Enum:
- result.WriteString(fmt.Sprintf("Type: %s (Enum)\n", t.Name))
- result.WriteString("Values:\n")
- for _, val := range t.EnumValues {
- result.WriteString(fmt.Sprintf(" - %s\n", val.Name))
- }
- default:
- result.WriteString(fmt.Sprintf("Type: %s (%s)\n", t.Name, t.Kind))
- }
- return result.String()
- }
- func introspectInputType(t *ast.Definition) string {
- var result strings.Builder
- result.WriteString(fmt.Sprintf("Type: %s (Input)\n", t.Name))
- if t.Description != "" {
- result.WriteString(fmt.Sprintf("Description: %s\n", t.Description))
- }
- result.WriteString("\nFields:\n")
- for _, field := range t.Fields {
- result.WriteString(formatInputField(field))
- }
- return result.String()
- }
- func formatField(field *ast.FieldDefinition) string {
- var result strings.Builder
- // Field name and type
- result.WriteString(fmt.Sprintf(" %s", field.Name))
- if len(field.Arguments) > 0 {
- result.WriteString("(")
- for i, arg := range field.Arguments {
- if i > 0 {
- result.WriteString(", ")
- }
- result.WriteString(fmt.Sprintf("%s: %s", arg.Name, formatType(arg.Type)))
- }
- result.WriteString(")")
- }
- result.WriteString(fmt.Sprintf(": %s", formatType(field.Type)))
- // Description
- if field.Description != "" {
- result.WriteString(fmt.Sprintf(" - %s", field.Description))
- }
- // Deprecation
- if field.Directives != nil {
- for _, d := range field.Directives {
- if d.Name == "deprecated" {
- result.WriteString(" [DEPRECATED]")
- if reason := d.Arguments.ForName("reason"); reason != nil {
- result.WriteString(fmt.Sprintf(" - %s", reason.Value.Raw))
- }
- }
- }
- }
- result.WriteString("\n")
- return result.String()
- }
- func formatInputField(field *ast.FieldDefinition) string {
- var result strings.Builder
- result.WriteString(fmt.Sprintf(" %s: %s", field.Name, formatType(field.Type)))
- if field.Description != "" {
- result.WriteString(fmt.Sprintf(" - %s", field.Description))
- }
- result.WriteString("\n")
- return result.String()
- }
- func formatType(t *ast.Type) string {
- if t == nil {
- return "Unknown"
- }
- base := t.Name()
- if t.NamedType != "" {
- base = t.NamedType
- }
- if t.Elem != nil {
- return fmt.Sprintf("[%s]", formatType(t.Elem))
- }
- if t.NonNull {
- return base + "!"
- }
- return base
- }
|