diff --git a/README.md b/README.md index 2662d91..a636a52 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Learn more about the protocol itself at . ```bash -go get github.com/coder/acp-go-sdk@v0.4.9 +go get github.com/coder/acp-go-sdk@v0.6.3 ``` ## Get Started diff --git a/acp_test.go b/acp_test.go index b7bf2a0..47bc889 100644 --- a/acp_test.go +++ b/acp_test.go @@ -352,7 +352,7 @@ func TestConnectionHandlesMessageOrdering(t *testing.T) { } if _, err := as.RequestPermission(context.Background(), RequestPermissionRequest{ SessionId: "test-session", - ToolCall: ToolCallUpdate{ + ToolCall: RequestPermissionToolCall{ Title: Ptr("Execute command"), Kind: ptr(ToolKindExecute), Status: ptr(ToolCallStatusPending), diff --git a/cmd/generate/internal/emit/types.go b/cmd/generate/internal/emit/types.go index 0cd600b..8d34475 100644 --- a/cmd/generate/internal/emit/types.go +++ b/cmd/generate/internal/emit/types.go @@ -9,17 +9,123 @@ import ( "slices" "sort" "strings" + "unicode" "github.com/coder/acp-go-sdk/cmd/generate/internal/ir" "github.com/coder/acp-go-sdk/cmd/generate/internal/load" "github.com/coder/acp-go-sdk/cmd/generate/internal/util" ) +// splitCamelCase splits a CamelCase string into words. +// Example: "RequestPermissionRequest" -> ["Request", "Permission", "Request"] +func splitCamelCase(s string) []string { + if s == "" { + return nil + } + var words []string + var current strings.Builder + + for i, r := range s { + if i > 0 && unicode.IsUpper(r) { + // Start new word on uppercase letter + if current.Len() > 0 { + words = append(words, current.String()) + current.Reset() + } + } + current.WriteRune(r) + } + if current.Len() > 0 { + words = append(words, current.String()) + } + return words +} + +// generateNestedTypeName applies multiple heuristics to create idiomatic nested type names +// while guaranteeing stability (name depends only on parent, field, and collision check). +// Panics if a collision is detected to catch codegen bugs early. +func generateNestedTypeName(parentName, rawFieldName string, usedNames map[string]bool) string { + // Heuristic 1: Ensure field name is properly capitalized first + fieldName := util.ToExportedField(rawFieldName) + + // Heuristic 2: Try RPC suffix stripping for Request/Response/Notification parents + // This handles cases like RequestPermissionRequest + ToolCall → RequestPermissionToolCall + for _, suffix := range []string{"Request", "Response", "Notification"} { + if strings.HasSuffix(parentName, suffix) { + baseName := strings.TrimSuffix(parentName, suffix) + if len(baseName) > 0 { + candidate := baseName + fieldName + if !usedNames[candidate] { + return candidate + } + } + } + } + + // Heuristic 3: Try word-boundary deduplication + // This handles cases like AgentNotification + ExtNotification → AgentExtNotification + parentWords := splitCamelCase(parentName) + fieldWords := splitCamelCase(fieldName) + + // Need at least 2 words in parent to consider deduplication + if len(parentWords) >= 2 && len(fieldWords) > 0 { + lastParentWord := parentWords[len(parentWords)-1] + firstFieldWord := fieldWords[0] + lastFieldWord := fieldWords[len(fieldWords)-1] + + if strings.EqualFold(lastParentWord, firstFieldWord) || strings.EqualFold(lastParentWord, lastFieldWord) { + // Remove last word from parent, then concatenate + parentWithoutLast := strings.Join(parentWords[:len(parentWords)-1], "") + if len(parentWithoutLast) > 0 { + candidate := parentWithoutLast + fieldName + if !usedNames[candidate] { + return candidate + } + } + } + } + + // Heuristic 4: Fall back to full concatenation + fullName := parentName + fieldName + if usedNames[fullName] { + // DEFENSIVE PROGRAMMING: This should never happen if we're tracking names correctly. + // If it does, it indicates a bug in the codegen logic. + panic(fmt.Sprintf("type name collision detected: %q already exists (parent: %q, field: %q)", + fullName, parentName, rawFieldName)) + } + return fullName +} + +// emitDocComment emits a multi-line doc comment for the given description. +// Properly handles newlines and paragraph breaks from JSON schema descriptions. +func emitDocComment(f *File, desc string) { + lines := util.FormatDocComment(desc) + for _, line := range lines { + f.Comment(line) + } +} + +// appendDocComments appends doc comment Code elements to a slice for struct field comments. +// Used when building struct field definitions with proper multi-line comment support. +func appendDocComments(codeSlice []Code, desc string) []Code { + lines := util.FormatDocComment(desc) + for _, line := range lines { + codeSlice = append(codeSlice, Comment(line)) + } + return codeSlice +} + // WriteTypesJen emits go/types_gen.go with all types and the Agent/Client interfaces. func WriteTypesJen(outDir string, schema *load.Schema, meta *load.Meta) error { f := NewFile("acp") f.HeaderComment("Code generated by acp-go-generator; DO NOT EDIT.") + // Track all type names to avoid collisions when generating nested types + usedTypeNames := make(map[string]bool) + for k := range schema.Defs { + usedTypeNames[k] = true + } + // Deterministic order keys := make([]string, 0, len(schema.Defs)) for k := range schema.Defs { @@ -33,8 +139,18 @@ func WriteTypesJen(outDir string, schema *load.Schema, meta *load.Meta) error { continue } + // DEFENSIVE PROGRAMMING: Ensure we're not about to emit a type that conflicts + // with a previously generated nested type. This should never happen since we + // pre-populate usedTypeNames with all schema definitions. + if usedTypeNames[name] && name != "" { + // This is expected for schema-defined types, but verify it's in the schema + if _, inSchema := schema.Defs[name]; !inSchema { + panic(fmt.Sprintf("BUG: attempting to emit type %q that was already generated as a nested type", name)) + } + } + if def.Description != "" { - f.Comment(util.SanitizeComment(def.Description)) + emitDocComment(f, def.Description) } switch { @@ -63,11 +179,11 @@ func WriteTypesJen(outDir string, schema *load.Schema, meta *load.Meta) error { } f.Line() case len(def.AnyOf) > 0: - emitUnion(f, name, def.AnyOf, false) + emitUnion(f, name, def, def.AnyOf, false, usedTypeNames) case len(def.OneOf) > 0 && !isStringConstUnion(def): // Generic union generation for non-enum oneOf // Use the same implementation, but require exactly one variant - emitUnion(f, name, def.OneOf, true) + emitUnion(f, name, def, def.OneOf, true, usedTypeNames) case ir.PrimaryType(def) == "object" && len(def.Properties) > 0: st := []Code{} req := map[string]struct{}{} @@ -79,6 +195,54 @@ func WriteTypesJen(outDir string, schema *load.Schema, meta *load.Meta) error { pkeys = append(pkeys, pk) } sort.Strings(pkeys) + + // Pre-generate nested struct types for inline object properties + nestedTypes := map[string]string{} // property name -> generated type name + for _, pk := range pkeys { + prop := def.Properties[pk] + // Detect inline objects: no $ref, type is object, has properties + if prop.Ref == "" && ir.PrimaryType(prop) == "object" && len(prop.Properties) > 0 { + nestedTypeName := generateNestedTypeName(name, pk, usedTypeNames) + nestedTypes[pk] = nestedTypeName + + // DEFENSIVE PROGRAMMING: Assert no collision before registering + if usedTypeNames[nestedTypeName] { + panic(fmt.Sprintf("BUG: nested type name collision: %q already registered", nestedTypeName)) + } + usedTypeNames[nestedTypeName] = true + + // Generate the nested struct type + if prop.Description != "" { + emitDocComment(f, prop.Description) + } + nestedFields := []Code{} + nestedReq := map[string]struct{}{} + for _, r := range prop.Required { + nestedReq[r] = struct{}{} + } + nestedPkeys := make([]string, 0, len(prop.Properties)) + for npk := range prop.Properties { + nestedPkeys = append(nestedPkeys, npk) + } + sort.Strings(nestedPkeys) + + for _, npk := range nestedPkeys { + nprop := prop.Properties[npk] + nfield := util.ToExportedField(npk) + if nprop.Description != "" { + nestedFields = appendDocComments(nestedFields, nprop.Description) + } + ntag := npk + if _, ok := nestedReq[npk]; !ok { + ntag = npk + ",omitempty" + } + nestedFields = append(nestedFields, Id(nfield).Add(jenTypeForOptional(nprop)).Tag(map[string]string{"json": ntag})) + } + f.Type().Id(nestedTypeName).Struct(nestedFields...) + f.Line() + } + } + // Track fields with schema defaults for generic (de)serialization type DefaultKind int const ( @@ -101,7 +265,7 @@ func WriteTypesJen(outDir string, schema *load.Schema, meta *load.Meta) error { prop := def.Properties[pk] field := util.ToExportedField(pk) if prop.Description != "" { - st = append(st, Comment(util.SanitizeComment(prop.Description))) + st = appendDocComments(st, prop.Description) } tag := pk // Detect defaults generically @@ -140,9 +304,16 @@ func WriteTypesJen(outDir string, schema *load.Schema, meta *load.Meta) error { if prop.Description != "" { st = append(st, Comment("")) } - st = append(st, Comment(util.SanitizeComment(fmt.Sprintf("Defaults to %s if unset.", dp.defaultJSON)))) + st = append(st, Comment(fmt.Sprintf("Defaults to %s if unset.", dp.defaultJSON))) } - st = append(st, Id(field).Add(jenTypeForOptional(prop)).Tag(map[string]string{"json": tag})) + // Use generated nested type if available, otherwise use jenTypeForOptional + var fieldType Code + if nestedTypeName, hasNested := nestedTypes[pk]; hasNested { + fieldType = Id(nestedTypeName) + } else { + fieldType = jenTypeForOptional(prop) + } + st = append(st, Id(field).Add(fieldType).Tag(map[string]string{"json": tag})) } f.Type().Id(name).Struct(st...) f.Line() @@ -238,7 +409,8 @@ func WriteTypesJen(outDir string, schema *load.Schema, meta *load.Meta) error { target = &agentExperimentalMethods } if desc := methodDescription(schema, mi); desc != "" { - *target = append(*target, Comment(util.SanitizeComment(desc))) + // Method descriptions can be multi-line, format them properly + *target = appendDocComments(*target, desc) } if mi.Notif != "" { name := ir.DispatchMethodNameForNotification(k, mi.Notif) @@ -280,7 +452,8 @@ func WriteTypesJen(outDir string, schema *load.Schema, meta *load.Meta) error { target = &clientTerminal } if desc := methodDescription(schema, mi); desc != "" { - *target = append(*target, Comment(util.SanitizeComment(desc))) + // Method descriptions can be multi-line, format them properly + *target = appendDocComments(*target, desc) } if mi.Notif != "" { name := ir.DispatchMethodNameForNotification(k, mi.Notif) @@ -544,7 +717,7 @@ func jenTypeForOptional(d *load.Definition) Code { // emitAvailableCommandInputJen generates a concrete variant type for anyOf and a thin union wrapper // that supports JSON unmarshal by probing object shape. Currently the schema defines one variant // (title: UnstructuredCommandInput) with a required 'hint' field. -func emitUnion(f *File, name string, defs []*load.Definition, exactlyOne bool) { +func emitUnion(f *File, name string, parentDef *load.Definition, defs []*load.Definition, exactlyOne bool, usedTypeNames map[string]bool) { type variantInfo struct { fieldName string typeName string @@ -557,20 +730,27 @@ func emitUnion(f *File, name string, defs []*load.Definition, exactlyOne bool) { } variants := []variantInfo{} discKey := "" - // discover discriminator key if present (any const property) - for _, v := range defs { - if v == nil { - continue - } - for k, pd := range v.Properties { - if pd != nil && pd.Const != nil { - discKey = k + // Use schema's explicit discriminator if available + if parentDef != nil && parentDef.Discriminator != nil { + discKey = parentDef.Discriminator.PropertyName + } + // Fallback: discover discriminator key by scanning for const properties + // (for backward compatibility with older schemas without discriminator metadata) + if discKey == "" { + for _, v := range defs { + if v == nil { + continue + } + for k, pd := range v.Properties { + if pd != nil && pd.Const != nil { + discKey = k + break + } + } + if discKey != "" { break } } - if discKey != "" { - break - } } for idx, v := range defs { if v == nil { @@ -586,22 +766,45 @@ func emitUnion(f *File, name string, defs []*load.Definition, exactlyOne bool) { if v.Ref != "" && strings.HasPrefix(v.Ref, "#/$defs/") { tname = v.Ref[len("#/$defs/"):] } else if v.Title != "" { - tname = v.Title + // Scope inline variant titles to parent union name with smart naming + tname = generateNestedTypeName(name, v.Title, usedTypeNames) + // DEFENSIVE PROGRAMMING: Assert no collision before registering + if usedTypeNames[tname] { + panic(fmt.Sprintf("BUG: variant type name collision: %q already registered (parent: %q, title: %q)", + tname, name, v.Title)) + } + usedTypeNames[tname] = true } else { if discKey != "" { if pd := v.Properties[discKey]; pd != nil && pd.Const != nil { s := fmt.Sprint(pd.Const) - tname = name + util.ToExportedField(s) + tname = generateNestedTypeName(name, s, usedTypeNames) + // DEFENSIVE PROGRAMMING: Assert no collision before registering + if usedTypeNames[tname] { + panic(fmt.Sprintf("BUG: variant type name collision: %q already registered (parent: %q, discriminator: %q)", + tname, name, s)) + } + usedTypeNames[tname] = true } } if tname == "" { tname = name + fmt.Sprintf("Variant%d", idx+1) + // DEFENSIVE PROGRAMMING: Assert no collision before registering + if usedTypeNames[tname] { + panic(fmt.Sprintf("BUG: variant type name collision: %q already registered (parent: %q)", + tname, name)) + } + usedTypeNames[tname] = true } } // Ensure Title-derived names are exported (e.g., "stdio" -> "Stdio"). tname = util.ToExportedField(tname) - fieldName := util.ToExportedField(tname) + + // Derive field name with priority: discriminator value > title > type name + fieldName := "" dv := "" + + // Priority 1: Use discriminator const value (most ergonomic) if discKey != "" { if pd := v.Properties[discKey]; pd != nil && pd.Const != nil { s := fmt.Sprint(pd.Const) @@ -609,9 +812,20 @@ func emitUnion(f *File, name string, defs []*load.Definition, exactlyOne bool) { dv = s } } + + // Priority 2: Use original title if no discriminator (e.g., "stdio") + if fieldName == "" && v.Title != "" { + fieldName = util.ToExportedField(v.Title) + } + + // Priority 3: Fall back to type name + if fieldName == "" { + fieldName = util.ToExportedField(tname) + } isObj := len(v.Properties) > 0 - // Skip phantom variants that have neither $ref nor object shape nor null (e.g., placeholders with only a title) - if !isObj && v.Ref == "" && !isNull { + // Skip phantom variants that have neither $ref nor object shape nor null nor title + // (but allow title-only variants like ExtMethodRequest to generate as empty structs) + if !isObj && v.Ref == "" && !isNull && v.Title == "" { continue } // collect const properties (e.g., type, outcome) @@ -623,9 +837,15 @@ func emitUnion(f *File, name string, defs []*load.Definition, exactlyOne bool) { } } } - if (isObj || isNull) && v.Ref == "" { + // Emit struct for inline variants (non-$ref) + if (isObj || isNull || v.Title != "") && v.Ref == "" { + // DEFENSIVE PROGRAMMING: Verify tname is registered before emitting + if !usedTypeNames[tname] { + panic(fmt.Sprintf("BUG: attempting to emit unregistered type: %q (parent union: %q)", tname, name)) + } + st := []Code{} - if !isNull { + if !isNull && isObj { req := map[string]struct{}{} for _, r := range v.Required { req[r] = struct{}{} @@ -636,13 +856,13 @@ func emitUnion(f *File, name string, defs []*load.Definition, exactlyOne bool) { } sort.Strings(pkeys) if v.Description != "" { - f.Comment(util.SanitizeComment(v.Description)) + emitDocComment(f, v.Description) } for _, pk := range pkeys { pDef := v.Properties[pk] field := util.ToExportedField(pk) if pDef.Description != "" { - st = append(st, Comment(util.SanitizeComment(pDef.Description))) + st = appendDocComments(st, pDef.Description) } tag := pk if _, ok := req[pk]; !ok { @@ -650,9 +870,31 @@ func emitUnion(f *File, name string, defs []*load.Definition, exactlyOne bool) { } st = append(st, Id(field).Add(jenTypeForOptional(pDef)).Tag(map[string]string{"json": tag})) } + } else if !isNull && !isObj && v.Title != "" { + // Title-only variants: check if they're extension types + // Extension types should preserve the raw payload, not drop it + isExtension := strings.Contains(strings.ToLower(v.Description), "extension") || + strings.Contains(v.Title, "Ext") + + if v.Description != "" { + emitDocComment(f, v.Description) + } + + if isExtension { + // Emit as type alias (=) to json.RawMessage to preserve marshal/unmarshal methods + // Using type alias ensures the RawMessage methods are inherited, unlike a defined type. + f.Type().Id(tname).Op("=").Qual("encoding/json", "RawMessage") + } else { + // Emit as empty struct (rare case for truly empty variants) + f.Type().Id(tname).Struct(st...) + } + f.Line() + // Skip the struct emission below for title-only variants + goto skipStructEmit } f.Type().Id(tname).Struct(st...) f.Line() + skipStructEmit: } variants = append(variants, variantInfo{ fieldName: fieldName, @@ -669,7 +911,7 @@ func emitUnion(f *File, name string, defs []*load.Definition, exactlyOne bool) { st := []Code{} for _, vi := range variants { if vi.description != "" { - st = append(st, Comment(util.SanitizeComment(vi.description))) + st = appendDocComments(st, vi.description) } st = append(st, Id(vi.fieldName).Op("*").Id(vi.typeName).Tag(map[string]string{"json": "-"})) } diff --git a/cmd/generate/internal/load/load.go b/cmd/generate/internal/load/load.go index f056f39..b932934 100644 --- a/cmd/generate/internal/load/load.go +++ b/cmd/generate/internal/load/load.go @@ -22,6 +22,12 @@ type Schema struct { Defs map[string]*Definition `json:"$defs"` } +// Discriminator specifies which property distinguishes union variants. +// Part of JSON Schema discriminator object support. +type Discriminator struct { + PropertyName string `json:"propertyName"` +} + // Definition is a partial JSON Schema node the generator cares about. type Definition struct { Description string `json:"description"` @@ -41,6 +47,9 @@ type Definition struct { // Default holds the JSON Schema default value, when present. // Used by generators to synthesize defaulting behavior. Default any `json:"default"` + // Discriminator specifies which property name distinguishes union variants. + // Part of JSON Schema's discriminator object support. + Discriminator *Discriminator `json:"discriminator,omitempty"` // boolSchema records whether this definition was a boolean schema (true/false). // JSON Schema allows boolean schemas, where true matches anything and false matches nothing. diff --git a/cmd/generate/internal/util/util.go b/cmd/generate/internal/util/util.go index 0ac7871..3a19416 100644 --- a/cmd/generate/internal/util/util.go +++ b/cmd/generate/internal/util/util.go @@ -8,6 +8,7 @@ import ( ) // SanitizeComment removes backticks and normalizes whitespace for Go comments. +// Deprecated: Use FormatDocComment for proper multi-line comment formatting. func SanitizeComment(s string) string { s = strings.ReplaceAll(s, "`", "'") lines := strings.Split(s, "\n") @@ -17,6 +18,35 @@ func SanitizeComment(s string) string { return strings.Join(lines, " ") } +// FormatDocComment formats a description as properly structured Go doc comment lines. +// Preserves paragraph breaks (double newlines) and handles line breaks within paragraphs. +// Returns slice of comment text without "//" prefix (caller should emit each as a comment line). +// +// Go doc comment conventions: +// - Each line of comment text becomes a separate "// line" +// - Blank lines (from \n\n) become "//" with no text +// - First line should be a complete sentence ending with period +func FormatDocComment(desc string) []string { + if desc == "" { + return nil + } + + // Replace backticks with single quotes (Go doc comments don't support backticks well) + desc = strings.ReplaceAll(desc, "`", "'") + + // Split into lines based on newlines from the JSON schema + lines := strings.Split(desc, "\n") + + var result []string + for _, line := range lines { + trimmed := strings.TrimSpace(line) + // Preserve blank lines as empty strings - jen will render them as "//" + result = append(result, trimmed) + } + + return result +} + // TitleWord uppercases the first rune and lowercases the rest. func TitleWord(s string) string { if s == "" { diff --git a/example/agent/main.go b/example/agent/main.go index 9ce478d..31717b0 100644 --- a/example/agent/main.go +++ b/example/agent/main.go @@ -205,7 +205,7 @@ func (a *exampleAgent) simulateTurn(ctx context.Context, sid string) error { // request permission for sensitive operation permResp, err := a.conn.RequestPermission(ctx, acp.RequestPermissionRequest{ SessionId: acp.SessionId(sid), - ToolCall: acp.ToolCallUpdate{ + ToolCall: acp.RequestPermissionToolCall{ ToolCallId: acp.ToolCallId("call_2"), Title: acp.Ptr("Modifying critical configuration file"), Kind: acp.Ptr(acp.ToolKindEdit), diff --git a/example_agent_test.go b/example_agent_test.go index c9cc94a..7a4053b 100644 --- a/example_agent_test.go +++ b/example_agent_test.go @@ -57,7 +57,7 @@ func (a *agentExample) Prompt(ctx context.Context, p PromptRequest) (PromptRespo // Ask the client for permission to proceed with the change. resp, _ := a.conn.RequestPermission(ctx, RequestPermissionRequest{ SessionId: p.SessionId, - ToolCall: ToolCallUpdate{ + ToolCall: RequestPermissionToolCall{ ToolCallId: ToolCallId("call_1"), Title: Ptr("Modifying configuration"), Kind: Ptr(ToolKindEdit), diff --git a/helpers.go b/helpers.go index cedfea2..f763904 100644 --- a/helpers.go +++ b/helpers.go @@ -36,9 +36,9 @@ func ResourceLinkBlock(name string, uri string) ContentBlock { } // ResourceBlock wraps an embedded resource as a content block. -func ResourceBlock(res EmbeddedResource) ContentBlock { +func ResourceBlock(res EmbeddedResourceResource) ContentBlock { return ContentBlock{Resource: &ContentBlockResource{ - Resource: res.Resource, + Resource: res, Type: "resource", }} } @@ -181,11 +181,11 @@ func WithStartRawOutput(v any) ToolCallStartOpt { } } -type ToolCallUpdateOpt func(tu *SessionUpdateToolCallUpdate) +type ToolCallUpdateOpt func(tu *SessionToolCallUpdate) // UpdateToolCall constructs a tool_call_update with the given ID and applies optional modifiers. func UpdateToolCall(id ToolCallId, opts ...ToolCallUpdateOpt) SessionUpdate { - tu := SessionUpdateToolCallUpdate{ToolCallId: id} + tu := SessionToolCallUpdate{ToolCallId: id} for _, opt := range opts { opt(&tu) } @@ -194,49 +194,49 @@ func UpdateToolCall(id ToolCallId, opts ...ToolCallUpdateOpt) SessionUpdate { // WithUpdateTitle sets the title for a tool_call_update. func WithUpdateTitle(t string) ToolCallUpdateOpt { - return func(tu *SessionUpdateToolCallUpdate) { + return func(tu *SessionToolCallUpdate) { tu.Title = Ptr(t) } } // WithUpdateKind sets the kind for a tool_call_update. func WithUpdateKind(k ToolKind) ToolCallUpdateOpt { - return func(tu *SessionUpdateToolCallUpdate) { + return func(tu *SessionToolCallUpdate) { tu.Kind = Ptr(k) } } // WithUpdateStatus sets the status for a tool_call_update. func WithUpdateStatus(s ToolCallStatus) ToolCallUpdateOpt { - return func(tu *SessionUpdateToolCallUpdate) { + return func(tu *SessionToolCallUpdate) { tu.Status = Ptr(s) } } // WithUpdateContent replaces the content collection for a tool_call_update. func WithUpdateContent(c []ToolCallContent) ToolCallUpdateOpt { - return func(tu *SessionUpdateToolCallUpdate) { + return func(tu *SessionToolCallUpdate) { tu.Content = c } } // WithUpdateLocations replaces the locations collection for a tool_call_update. func WithUpdateLocations(l []ToolCallLocation) ToolCallUpdateOpt { - return func(tu *SessionUpdateToolCallUpdate) { + return func(tu *SessionToolCallUpdate) { tu.Locations = l } } // WithUpdateRawInput sets rawInput for a tool_call_update. func WithUpdateRawInput(v any) ToolCallUpdateOpt { - return func(tu *SessionUpdateToolCallUpdate) { + return func(tu *SessionToolCallUpdate) { tu.RawInput = v } } // WithUpdateRawOutput sets rawOutput for a tool_call_update. func WithUpdateRawOutput(v any) ToolCallUpdateOpt { - return func(tu *SessionUpdateToolCallUpdate) { + return func(tu *SessionToolCallUpdate) { tu.RawOutput = v } } diff --git a/json_parity_test.go b/json_parity_test.go index 13d1aa3..baa8f45 100644 --- a/json_parity_test.go +++ b/json_parity_test.go @@ -85,13 +85,13 @@ func TestJSONGolden_ContentBlocks(t *testing.T) { t.Run("content_resource_text", runGolden( func() ContentBlock { res := EmbeddedResourceResource{TextResourceContents: &TextResourceContents{Uri: "file:///home/user/script.py", MimeType: Ptr("text/x-python"), Text: "def hello():\n print('Hello, world!')"}} - return ResourceBlock(EmbeddedResource{Resource: res}) + return ResourceBlock(res) }, )) t.Run("content_resource_blob", runGolden( func() ContentBlock { res := EmbeddedResourceResource{BlobResourceContents: &BlobResourceContents{Uri: "file:///home/user/document.pdf", MimeType: Ptr("application/pdf"), Blob: ""}} - return ResourceBlock(EmbeddedResource{Resource: res}) + return ResourceBlock(res) }, )) t.Run("content_resource_link", runGolden( @@ -204,7 +204,7 @@ func TestJSONGolden_SessionUpdates(t *testing.T) { )) t.Run("session_update_tool_call_update_content", runGolden( func() SessionUpdate { - return SessionUpdate{ToolCallUpdate: &SessionUpdateToolCallUpdate{ToolCallId: "call_001", Status: Ptr(ToolCallStatusInProgress), Content: []ToolCallContent{ToolContent(TextBlock("Found 3 configuration files..."))}}} + return SessionUpdate{ToolCallUpdate: &SessionToolCallUpdate{ToolCallId: "call_001", Status: Ptr(ToolCallStatusInProgress), Content: []ToolCallContent{ToolContent(TextBlock("Found 3 configuration files..."))}}} }, func() SessionUpdate { return UpdateToolCall("call_001", WithUpdateStatus(ToolCallStatusInProgress), WithUpdateContent([]ToolCallContent{ToolContent(TextBlock("Found 3 configuration files..."))})) @@ -238,7 +238,7 @@ func TestJSONGolden_MethodPayloads(t *testing.T) { return NewSessionRequest{ Cwd: "/home/user/project", McpServers: []McpServer{ { - Stdio: &Stdio{ + Stdio: &McpServerStdio{ Name: "filesystem", Command: "/path/to/mcp-server", Args: []string{"--stdio"}, @@ -250,7 +250,7 @@ func TestJSONGolden_MethodPayloads(t *testing.T) { })) t.Run("new_session_response", runGolden(func() NewSessionResponse { return NewSessionResponse{SessionId: "sess_abc123def456"} })) t.Run("prompt_request", runGolden(func() PromptRequest { - return PromptRequest{SessionId: "sess_abc123def456", Prompt: []ContentBlock{TextBlock("Can you analyze this code for potential issues?"), ResourceBlock(EmbeddedResource{Resource: EmbeddedResourceResource{TextResourceContents: &TextResourceContents{Uri: "file:///home/user/project/main.py", MimeType: Ptr("text/x-python"), Text: "def process_data(items):\n for item in items:\n print(item)"}}})}} + return PromptRequest{SessionId: "sess_abc123def456", Prompt: []ContentBlock{TextBlock("Can you analyze this code for potential issues?"), ResourceBlock(EmbeddedResourceResource{TextResourceContents: &TextResourceContents{Uri: "file:///home/user/project/main.py", MimeType: Ptr("text/x-python"), Text: "def process_data(items):\n for item in items:\n print(item)"}})}} })) t.Run("fs_read_text_file_request", runGolden(func() ReadTextFileRequest { line, limit := 10, 50 @@ -263,7 +263,7 @@ func TestJSONGolden_MethodPayloads(t *testing.T) { return WriteTextFileRequest{SessionId: "sess_abc123def456", Path: "/home/user/project/config.json", Content: "{\n \"debug\": true,\n \"version\": \"1.0.0\"\n}"} })) t.Run("request_permission_request", runGolden(func() RequestPermissionRequest { - return RequestPermissionRequest{SessionId: "sess_abc123def456", ToolCall: ToolCallUpdate{ToolCallId: "call_001"}, Options: []PermissionOption{{OptionId: "allow-once", Name: "Allow once", Kind: PermissionOptionKindAllowOnce}, {OptionId: "reject-once", Name: "Reject", Kind: PermissionOptionKindRejectOnce}}} + return RequestPermissionRequest{SessionId: "sess_abc123def456", ToolCall: RequestPermissionToolCall{ToolCallId: "call_001"}, Options: []PermissionOption{{OptionId: "allow-once", Name: "Allow once", Kind: PermissionOptionKindAllowOnce}, {OptionId: "reject-once", Name: "Reject", Kind: PermissionOptionKindRejectOnce}}} })) t.Run("request_permission_response_selected", runGolden(func() RequestPermissionResponse { return RequestPermissionResponse{Outcome: RequestPermissionOutcome{Selected: &RequestPermissionOutcomeSelected{Outcome: "selected", OptionId: "allow-once"}}} diff --git a/schema/schema.json b/schema/schema.json index 7db21b6..b33f489 100644 --- a/schema/schema.json +++ b/schema/schema.json @@ -46,6 +46,123 @@ "description": "All possible notifications that an agent can send to a client.\n\nThis enum is used internally for routing RPC notifications. You typically won't need\nto use this directly - use the notification methods on the [`Client`] trait instead.\n\nNotifications do not expect a response.", "x-docs-ignore": true }, + "AgentOutgoingMessage": { + "anyOf": [ + { + "properties": { + "id": { + "anyOf": [ + { + "title": "null", + "type": "null" + }, + { + "format": "int64", + "title": "number", + "type": "integer" + }, + { + "title": "string", + "type": "string" + } + ], + "description": "JSON RPC Request Id\n\nAn identifier established by the Client that MUST contain a String, Number, or NULL value if included. If it is not included it is assumed to be a notification. The value SHOULD normally not be Null [1] and Numbers SHOULD NOT contain fractional parts [2]\n\nThe Server MUST reply with the same value in the Response object if included. This member is used to correlate the context between the two objects.\n\n[1] The use of Null as a value for the id member in a Request object is discouraged, because this specification uses a value of Null for Responses with an unknown id. Also, because JSON-RPC 1.0 uses an id value of Null for Notifications this could cause confusion in handling.\n\n[2] Fractional parts may be problematic, since many decimal fractions cannot be represented exactly as binary fractions." + }, + "method": { + "type": "string" + }, + "params": { + "anyOf": [ + { + "$ref": "#/$defs/AgentRequest" + }, + { + "type": "null" + } + ] + } + }, + "required": ["id", "method"], + "title": "Request", + "type": "object" + }, + { + "oneOf": [ + { + "properties": { + "result": { + "$ref": "#/$defs/AgentResponse" + } + }, + "required": ["result"], + "type": "object" + }, + { + "properties": { + "error": { + "$ref": "#/$defs/Error" + } + }, + "required": ["error"], + "type": "object" + } + ], + "properties": { + "id": { + "anyOf": [ + { + "title": "null", + "type": "null" + }, + { + "format": "int64", + "title": "number", + "type": "integer" + }, + { + "title": "string", + "type": "string" + } + ], + "description": "JSON RPC Request Id\n\nAn identifier established by the Client that MUST contain a String, Number, or NULL value if included. If it is not included it is assumed to be a notification. The value SHOULD normally not be Null [1] and Numbers SHOULD NOT contain fractional parts [2]\n\nThe Server MUST reply with the same value in the Response object if included. This member is used to correlate the context between the two objects.\n\n[1] The use of Null as a value for the id member in a Request object is discouraged, because this specification uses a value of Null for Responses with an unknown id. Also, because JSON-RPC 1.0 uses an id value of Null for Notifications this could cause confusion in handling.\n\n[2] Fractional parts may be problematic, since many decimal fractions cannot be represented exactly as binary fractions." + } + }, + "required": ["id"], + "title": "Response", + "type": "object" + }, + { + "properties": { + "method": { + "type": "string" + }, + "params": { + "anyOf": [ + { + "$ref": "#/$defs/AgentNotification" + }, + { + "type": "null" + } + ] + } + }, + "required": ["method"], + "title": "Notification", + "type": "object" + } + ], + "description": "A message (request, response, or notification) with `\"jsonrpc\": \"2.0\"` specified as\n[required by JSON-RPC 2.0 Specification][1].\n\n[1]: https://www.jsonrpc.org/specification#compatibility", + "properties": { + "jsonrpc": { + "enum": ["2.0"], + "type": "string" + } + }, + "required": ["jsonrpc"], + "type": "object", + "x-docs-ignore": true + }, "AgentRequest": { "anyOf": [ { @@ -155,32 +272,6 @@ }, "type": "object" }, - "AudioContent": { - "description": "Audio provided to or from an LLM.", - "properties": { - "_meta": { - "description": "Extension point for implementations" - }, - "annotations": { - "anyOf": [ - { - "$ref": "#/$defs/Annotations" - }, - { - "type": "null" - } - ] - }, - "data": { - "type": "string" - }, - "mimeType": { - "type": "string" - } - }, - "required": ["data", "mimeType"], - "type": "object" - }, "AuthMethod": { "description": "Describes an available authentication method.", "properties": { @@ -352,6 +443,123 @@ "description": "All possible notifications that a client can send to an agent.\n\nThis enum is used internally for routing RPC notifications. You typically won't need\nto use this directly - use the notification methods on the [`Agent`] trait instead.\n\nNotifications do not expect a response.", "x-docs-ignore": true }, + "ClientOutgoingMessage": { + "anyOf": [ + { + "properties": { + "id": { + "anyOf": [ + { + "title": "null", + "type": "null" + }, + { + "format": "int64", + "title": "number", + "type": "integer" + }, + { + "title": "string", + "type": "string" + } + ], + "description": "JSON RPC Request Id\n\nAn identifier established by the Client that MUST contain a String, Number, or NULL value if included. If it is not included it is assumed to be a notification. The value SHOULD normally not be Null [1] and Numbers SHOULD NOT contain fractional parts [2]\n\nThe Server MUST reply with the same value in the Response object if included. This member is used to correlate the context between the two objects.\n\n[1] The use of Null as a value for the id member in a Request object is discouraged, because this specification uses a value of Null for Responses with an unknown id. Also, because JSON-RPC 1.0 uses an id value of Null for Notifications this could cause confusion in handling.\n\n[2] Fractional parts may be problematic, since many decimal fractions cannot be represented exactly as binary fractions." + }, + "method": { + "type": "string" + }, + "params": { + "anyOf": [ + { + "$ref": "#/$defs/ClientRequest" + }, + { + "type": "null" + } + ] + } + }, + "required": ["id", "method"], + "title": "Request", + "type": "object" + }, + { + "oneOf": [ + { + "properties": { + "result": { + "$ref": "#/$defs/ClientResponse" + } + }, + "required": ["result"], + "type": "object" + }, + { + "properties": { + "error": { + "$ref": "#/$defs/Error" + } + }, + "required": ["error"], + "type": "object" + } + ], + "properties": { + "id": { + "anyOf": [ + { + "title": "null", + "type": "null" + }, + { + "format": "int64", + "title": "number", + "type": "integer" + }, + { + "title": "string", + "type": "string" + } + ], + "description": "JSON RPC Request Id\n\nAn identifier established by the Client that MUST contain a String, Number, or NULL value if included. If it is not included it is assumed to be a notification. The value SHOULD normally not be Null [1] and Numbers SHOULD NOT contain fractional parts [2]\n\nThe Server MUST reply with the same value in the Response object if included. This member is used to correlate the context between the two objects.\n\n[1] The use of Null as a value for the id member in a Request object is discouraged, because this specification uses a value of Null for Responses with an unknown id. Also, because JSON-RPC 1.0 uses an id value of Null for Notifications this could cause confusion in handling.\n\n[2] Fractional parts may be problematic, since many decimal fractions cannot be represented exactly as binary fractions." + } + }, + "required": ["id"], + "title": "Response", + "type": "object" + }, + { + "properties": { + "method": { + "type": "string" + }, + "params": { + "anyOf": [ + { + "$ref": "#/$defs/ClientNotification" + }, + { + "type": "null" + } + ] + } + }, + "required": ["method"], + "title": "Notification", + "type": "object" + } + ], + "description": "A message (request, response, or notification) with `\"jsonrpc\": \"2.0\"` specified as\n[required by JSON-RPC 2.0 Specification][1].\n\n[1]: https://www.jsonrpc.org/specification#compatibility", + "properties": { + "jsonrpc": { + "enum": ["2.0"], + "type": "string" + } + }, + "required": ["jsonrpc"], + "type": "object", + "x-docs-ignore": true + }, "ClientRequest": { "anyOf": [ { @@ -440,9 +648,12 @@ }, "ContentBlock": { "description": "Content blocks represent displayable information in the Agent Client Protocol.\n\nThey provide a structured way to handle various types of user-facing content—whether\nit's text from language models, images for analysis, or embedded resources for context.\n\nContent blocks appear in:\n- User prompts sent via `session/prompt`\n- Language model output streamed through `session/update` notifications\n- Progress updates and results from tool calls\n\nThis structure is compatible with the Model Context Protocol (MCP), enabling\nagents to seamlessly forward content from MCP tool outputs without transformation.\n\nSee protocol docs: [Content](https://agentclientprotocol.com/protocol/content)", + "discriminator": { + "propertyName": "type" + }, "oneOf": [ { - "description": "Plain text content\n\nAll agents MUST support text content blocks in prompts.", + "description": "Text content. May be plain text or formatted with Markdown.\n\nAll agents MUST support text content blocks in prompts.\nClients SHOULD render this text as Markdown.", "properties": { "_meta": { "description": "Extension point for implementations" @@ -663,29 +874,6 @@ "x-method": "terminal/create", "x-side": "client" }, - "EmbeddedResource": { - "description": "The contents of a resource, embedded into a prompt or tool call result.", - "properties": { - "_meta": { - "description": "Extension point for implementations" - }, - "annotations": { - "anyOf": [ - { - "$ref": "#/$defs/Annotations" - }, - { - "type": "null" - } - ] - }, - "resource": { - "$ref": "#/$defs/EmbeddedResourceResource" - } - }, - "required": ["resource"], - "type": "object" - }, "EmbeddedResourceResource": { "anyOf": [ { @@ -717,6 +905,25 @@ "required": ["name", "value"], "type": "object" }, + "Error": { + "description": "JSON-RPC error object.\n\nRepresents an error that occurred during method execution, following the\nJSON-RPC 2.0 error object specification with optional additional data.\n\nSee protocol docs: [JSON-RPC Error Object](https://www.jsonrpc.org/specification#error_object)", + "properties": { + "code": { + "description": "A number indicating the error type that occurred.\nThis must be an integer as defined in the JSON-RPC specification.", + "format": "int32", + "type": "integer" + }, + "data": { + "description": "Optional primitive or structured value that contains additional information about the error.\nThis may include debugging information or context-specific details." + }, + "message": { + "description": "A string providing a short description of the error.\nThe message should be limited to a concise single sentence.", + "type": "string" + } + }, + "required": ["code", "message"], + "type": "object" + }, "FileSystemCapability": { "description": "File system capabilities that a client may support.\n\nSee protocol docs: [FileSystem](https://agentclientprotocol.com/protocol/initialization#filesystem)", "properties": { @@ -754,33 +961,23 @@ "required": ["name", "value"], "type": "object" }, - "ImageContent": { - "description": "An image provided to or from an LLM.", + "Implementation": { + "description": "Describes the name and version of an MCP implementation, with an optional\ntitle for UI representation.", "properties": { - "_meta": { - "description": "Extension point for implementations" - }, - "annotations": { - "anyOf": [ - { - "$ref": "#/$defs/Annotations" - }, - { - "type": "null" - } - ] - }, - "data": { - "type": "string" - }, - "mimeType": { + "name": { + "description": "Intended for programmatic or logical use, but can be used as a display\nname fallback if title isn’t present.", "type": "string" }, - "uri": { + "title": { + "description": "Intended for UI and end-user contexts — optimized to be human-readable\nand easily understood.\n\nIf not provided, the name should be used for display.", "type": ["string", "null"] + }, + "version": { + "description": "Version of the implementation. Can be displayed to the user or used\nfor debugging or metrics purposes.", + "type": "string" } }, - "required": ["data", "mimeType"], + "required": ["name", "version"], "type": "object" }, "InitializeRequest": { @@ -800,6 +997,17 @@ }, "description": "Capabilities supported by the client." }, + "clientInfo": { + "anyOf": [ + { + "$ref": "#/$defs/Implementation" + }, + { + "type": "null" + } + ], + "description": "Information about the Client name and version sent to the Agent.\n\nNote: in future versions of the protocol, this will be required." + }, "protocolVersion": { "$ref": "#/$defs/ProtocolVersion", "description": "The latest protocol version supported by the client." @@ -832,6 +1040,17 @@ }, "description": "Capabilities supported by the agent." }, + "agentInfo": { + "anyOf": [ + { + "$ref": "#/$defs/Implementation" + }, + { + "type": "null" + } + ], + "description": "Information about the Agent name and version sent to the Client.\n\nNote: in future versions of the protocol, this will be required." + }, "authMethods": { "default": [], "description": "Authentication methods supported by the agent.", @@ -1045,7 +1264,10 @@ "type": "object" } ], - "description": "Configuration for connecting to an MCP (Model Context Protocol) server.\n\nMCP servers provide tools and context that the agent can use when\nprocessing prompts.\n\nSee protocol docs: [MCP Servers](https://agentclientprotocol.com/protocol/session-setup#mcp-servers)" + "description": "Configuration for connecting to an MCP (Model Context Protocol) server.\n\nMCP servers provide tools and context that the agent can use when\nprocessing prompts.\n\nSee protocol docs: [MCP Servers](https://agentclientprotocol.com/protocol/session-setup#mcp-servers)", + "discriminator": { + "propertyName": "type" + } }, "ModelId": { "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nA unique identifier for a model.", @@ -1185,23 +1407,6 @@ } ] }, - "Plan": { - "description": "An execution plan for accomplishing complex tasks.\n\nPlans consist of multiple entries representing individual tasks or goals.\nAgents report plans to clients to provide visibility into their execution strategy.\nPlans can evolve during execution as the agent discovers new requirements or completes tasks.\n\nSee protocol docs: [Agent Plan](https://agentclientprotocol.com/protocol/agent-plan)", - "properties": { - "_meta": { - "description": "Extension point for implementations" - }, - "entries": { - "description": "The list of tasks to be accomplished.\n\nWhen updating a plan, the agent must send a complete list of all entries\nwith their current status. The client replaces the entire plan with each update.", - "items": { - "$ref": "#/$defs/PlanEntry" - }, - "type": "array" - } - }, - "required": ["entries"], - "type": "object" - }, "PlanEntry": { "description": "A single entry in the execution plan.\n\nRepresents a task or goal that the assistant intends to accomplish\nas part of fulfilling the user's request.\nSee protocol docs: [Plan Entries](https://agentclientprotocol.com/protocol/agent-plan#plan-entries)", "properties": { @@ -1414,6 +1619,9 @@ }, "RequestPermissionOutcome": { "description": "The outcome of a permission request.", + "discriminator": { + "propertyName": "outcome" + }, "oneOf": [ { "description": "The prompt turn was cancelled before the user responded.\n\nWhen a client sends a `session/cancel` notification to cancel an ongoing\nprompt turn, it MUST respond to all pending `session/request_permission`\nrequests with this `Cancelled` outcome.\n\nSee protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)", @@ -1461,8 +1669,64 @@ "description": "The session ID for this request." }, "toolCall": { - "$ref": "#/$defs/ToolCallUpdate", - "description": "Details about the tool call requiring permission." + "description": "Details about the tool call requiring permission.", + "properties": { + "_meta": { + "description": "Extension point for implementations" + }, + "content": { + "description": "Replace the content collection.", + "items": { + "$ref": "#/$defs/ToolCallContent" + }, + "type": ["array", "null"] + }, + "kind": { + "anyOf": [ + { + "$ref": "#/$defs/ToolKind" + }, + { + "type": "null" + } + ], + "description": "Update the tool kind." + }, + "locations": { + "description": "Replace the locations collection.", + "items": { + "$ref": "#/$defs/ToolCallLocation" + }, + "type": ["array", "null"] + }, + "rawInput": { + "description": "Update the raw input." + }, + "rawOutput": { + "description": "Update the raw output." + }, + "status": { + "anyOf": [ + { + "$ref": "#/$defs/ToolCallStatus" + }, + { + "type": "null" + } + ], + "description": "Update the execution status." + }, + "title": { + "description": "Update the human-readable title.", + "type": ["string", "null"] + }, + "toolCallId": { + "$ref": "#/$defs/ToolCallId", + "description": "The ID of the tool call being updated." + } + }, + "required": ["toolCallId"], + "type": "object" } }, "required": ["sessionId", "toolCall", "options"], @@ -1486,45 +1750,6 @@ "x-method": "session/request_permission", "x-side": "client" }, - "ResourceLink": { - "description": "A resource that the server is capable of reading, included in a prompt or tool call result.", - "properties": { - "_meta": { - "description": "Extension point for implementations" - }, - "annotations": { - "anyOf": [ - { - "$ref": "#/$defs/Annotations" - }, - { - "type": "null" - } - ] - }, - "description": { - "type": ["string", "null"] - }, - "mimeType": { - "type": ["string", "null"] - }, - "name": { - "type": "string" - }, - "size": { - "format": "int64", - "type": ["integer", "null"] - }, - "title": { - "type": ["string", "null"] - }, - "uri": { - "type": "string" - } - }, - "required": ["name", "uri"], - "type": "object" - }, "Role": { "description": "The sender or recipient of messages and data in a conversation.", "enum": ["assistant", "user"], @@ -1621,12 +1846,19 @@ }, "SessionUpdate": { "description": "Different types of updates that can be sent during session processing.\n\nThese updates provide real-time feedback about the agent's progress.\n\nSee protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)", + "discriminator": { + "propertyName": "sessionUpdate" + }, "oneOf": [ { "description": "A chunk of the user's message being streamed.", "properties": { + "_meta": { + "description": "Extension point for implementations" + }, "content": { - "$ref": "#/$defs/ContentBlock" + "$ref": "#/$defs/ContentBlock", + "description": "A single item of content" }, "sessionUpdate": { "const": "user_message_chunk", @@ -1639,8 +1871,12 @@ { "description": "A chunk of the agent's response being streamed.", "properties": { + "_meta": { + "description": "Extension point for implementations" + }, "content": { - "$ref": "#/$defs/ContentBlock" + "$ref": "#/$defs/ContentBlock", + "description": "A single item of content" }, "sessionUpdate": { "const": "agent_message_chunk", @@ -1653,8 +1889,12 @@ { "description": "A chunk of the agent's internal reasoning being streamed.", "properties": { + "_meta": { + "description": "Extension point for implementations" + }, "content": { - "$ref": "#/$defs/ContentBlock" + "$ref": "#/$defs/ContentBlock", + "description": "A single item of content" }, "sessionUpdate": { "const": "agent_thought_chunk", @@ -1802,7 +2042,11 @@ { "description": "Available commands are ready or have changed", "properties": { + "_meta": { + "description": "Extension point for implementations" + }, "availableCommands": { + "description": "Commands the agent can execute", "items": { "$ref": "#/$defs/AvailableCommand" }, @@ -1819,8 +2063,12 @@ { "description": "The current mode of the session has changed\n\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)", "properties": { + "_meta": { + "description": "Extension point for implementations" + }, "currentModeId": { - "$ref": "#/$defs/SessionModeId" + "$ref": "#/$defs/SessionModeId", + "description": "The ID of the current mode" }, "sessionUpdate": { "const": "current_mode_update", @@ -1855,7 +2103,7 @@ "SetSessionModeResponse": { "description": "Response to `session/set_mode` method.", "properties": { - "meta": true + "_meta": true }, "type": "object", "x-method": "session/set_mode", @@ -1992,29 +2240,6 @@ "x-method": "terminal/output", "x-side": "client" }, - "TextContent": { - "description": "Text provided to or from an LLM.", - "properties": { - "_meta": { - "description": "Extension point for implementations" - }, - "annotations": { - "anyOf": [ - { - "$ref": "#/$defs/Annotations" - }, - { - "type": "null" - } - ] - }, - "text": { - "type": "string" - } - }, - "required": ["text"], - "type": "object" - }, "TextResourceContents": { "description": "Text-based resource contents.", "properties": { @@ -2034,54 +2259,11 @@ "required": ["text", "uri"], "type": "object" }, - "ToolCall": { - "description": "Represents a tool call that the language model has requested.\n\nTool calls are actions that the agent executes on behalf of the language model,\nsuch as reading files, executing code, or fetching data from external sources.\n\nSee protocol docs: [Tool Calls](https://agentclientprotocol.com/protocol/tool-calls)", - "properties": { - "_meta": { - "description": "Extension point for implementations" - }, - "content": { - "description": "Content produced by the tool call.", - "items": { - "$ref": "#/$defs/ToolCallContent" - }, - "type": "array" - }, - "kind": { - "$ref": "#/$defs/ToolKind", - "description": "The category of tool being invoked.\nHelps clients choose appropriate icons and UI treatment." - }, - "locations": { - "description": "File locations affected by this tool call.\nEnables \"follow-along\" features in clients.", - "items": { - "$ref": "#/$defs/ToolCallLocation" - }, - "type": "array" - }, - "rawInput": { - "description": "Raw input parameters sent to the tool." - }, - "rawOutput": { - "description": "Raw output returned by the tool." - }, - "status": { - "$ref": "#/$defs/ToolCallStatus", - "description": "Current execution status of the tool call." - }, - "title": { - "description": "Human-readable title describing what the tool is doing.", - "type": "string" - }, - "toolCallId": { - "$ref": "#/$defs/ToolCallId", - "description": "Unique identifier for this tool call within the session." - } - }, - "required": ["toolCallId", "title"], - "type": "object" - }, "ToolCallContent": { "description": "Content produced by a tool call.\n\nTool calls can produce different types of content including\nstandard content blocks (text, images) or file diffs.\n\nSee protocol docs: [Content](https://agentclientprotocol.com/protocol/tool-calls#content)", + "discriminator": { + "propertyName": "type" + }, "oneOf": [ { "description": "Standard content block (text, images, resources).", @@ -2189,66 +2371,6 @@ } ] }, - "ToolCallUpdate": { - "description": "An update to an existing tool call.\n\nUsed to report progress and results as tools execute. All fields except\nthe tool call ID are optional - only changed fields need to be included.\n\nSee protocol docs: [Updating](https://agentclientprotocol.com/protocol/tool-calls#updating)", - "properties": { - "_meta": { - "description": "Extension point for implementations" - }, - "content": { - "description": "Replace the content collection.", - "items": { - "$ref": "#/$defs/ToolCallContent" - }, - "type": ["array", "null"] - }, - "kind": { - "anyOf": [ - { - "$ref": "#/$defs/ToolKind" - }, - { - "type": "null" - } - ], - "description": "Update the tool kind." - }, - "locations": { - "description": "Replace the locations collection.", - "items": { - "$ref": "#/$defs/ToolCallLocation" - }, - "type": ["array", "null"] - }, - "rawInput": { - "description": "Update the raw input." - }, - "rawOutput": { - "description": "Update the raw output." - }, - "status": { - "anyOf": [ - { - "$ref": "#/$defs/ToolCallStatus" - }, - { - "type": "null" - } - ], - "description": "Update the execution status." - }, - "title": { - "description": "Update the human-readable title.", - "type": ["string", "null"] - }, - "toolCallId": { - "$ref": "#/$defs/ToolCallId", - "description": "The ID of the tool call being updated." - } - }, - "required": ["toolCallId"], - "type": "object" - }, "ToolKind": { "description": "Categories of tools that can be invoked.\n\nTool kinds help clients choose appropriate icons and optimize how they\ndisplay tool execution progress.\n\nSee protocol docs: [Creating](https://agentclientprotocol.com/protocol/tool-calls#creating)", "oneOf": [ @@ -2384,28 +2506,12 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "anyOf": [ { - "$ref": "#/$defs/AgentRequest", - "title": "ClientRequest" - }, - { - "$ref": "#/$defs/ClientResponse", - "title": "ClientResponse" - }, - { - "$ref": "#/$defs/ClientNotification", - "title": "ClientNotification" - }, - { - "$ref": "#/$defs/ClientRequest", - "title": "AgentRequest" - }, - { - "$ref": "#/$defs/AgentResponse", - "title": "AgentResponse" + "$ref": "#/$defs/AgentOutgoingMessage", + "title": "AgentOutgoingMessage" }, { - "$ref": "#/$defs/AgentNotification", - "title": "AgentNotification" + "$ref": "#/$defs/ClientOutgoingMessage", + "title": "ClientOutgoingMessage" } ] } diff --git a/schema/version b/schema/version index 76914dd..844f6a9 100644 --- a/schema/version +++ b/schema/version @@ -1 +1 @@ -0.4.9 +0.6.3 diff --git a/types_gen.go b/types_gen.go index 7c3eb7a..3e20dea 100644 --- a/types_gen.go +++ b/types_gen.go @@ -9,7 +9,12 @@ import ( "fmt" ) -// Capabilities supported by the agent. Advertised during initialization to inform the client about available features and content types. See protocol docs: [Agent Capabilities](https://agentclientprotocol.com/protocol/initialization#agent-capabilities) +// Capabilities supported by the agent. +// +// Advertised during initialization to inform the client about +// available features and content types. +// +// See protocol docs: [Agent Capabilities](https://agentclientprotocol.com/protocol/initialization#agent-capabilities) type AgentCapabilities struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` @@ -66,10 +71,42 @@ func (v *AgentCapabilities) UnmarshalJSON(b []byte) error { return nil } -// All possible notifications that an agent can send to a client. This enum is used internally for routing RPC notifications. You typically won't need to use this directly - use the notification methods on the ['Client'] trait instead. Notifications do not expect a response. +// All possible notifications that an agent can send to a client. +// +// This enum is used internally for routing RPC notifications. You typically won't need +// to use this directly - use the notification methods on the ['Client'] trait instead. +// +// Notifications do not expect a response. +// Handles extension notifications from the agent. +// +// Allows the Agent to send an arbitrary notification that is not part of the ACP spec. +// Extension notifications provide a way to send one-way messages for custom functionality +// while maintaining protocol compatibility. +// +// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) +type AgentExtNotification = json.RawMessage + type AgentNotification struct { - // Handles session update notifications from the agent. This is a notification endpoint (no response expected) that receives real-time updates about session progress, including message chunks, tool calls, and execution plans. Note: Clients SHOULD continue accepting tool call updates even after sending a 'session/cancel' notification, as the agent may send final updates before responding with the cancelled stop reason. See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output) + // Handles session update notifications from the agent. + // + // This is a notification endpoint (no response expected) that receives + // real-time updates about session progress, including message chunks, + // tool calls, and execution plans. + // + // Note: Clients SHOULD continue accepting tool call updates even after + // sending a 'session/cancel' notification, as the agent may send final + // updates before responding with the cancelled stop reason. + // + // See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output) SessionNotification *SessionNotification `json:"-"` + // Handles extension notifications from the agent. + // + // Allows the Agent to send an arbitrary notification that is not part of the ACP spec. + // Extension notifications provide a way to send one-way messages for custom functionality + // while maintaining protocol compatibility. + // + // See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + ExtNotification *AgentExtNotification `json:"-"` } func (u *AgentNotification) UnmarshalJSON(b []byte) error { @@ -84,6 +121,13 @@ func (u *AgentNotification) UnmarshalJSON(b []byte) error { return nil } } + { + var v AgentExtNotification + if json.Unmarshal(b, &v) == nil { + u.ExtNotification = &v + return nil + } + } return nil } func (u AgentNotification) MarshalJSON() ([]byte, error) { @@ -98,27 +142,274 @@ func (u AgentNotification) MarshalJSON() ([]byte, error) { } return json.Marshal(m) } + if u.ExtNotification != nil { + var m map[string]any + _b, _e := json.Marshal(*u.ExtNotification) + if _e != nil { + return []byte{}, _e + } + if json.Unmarshal(_b, &m) != nil { + return []byte{}, errors.New("invalid variant payload") + } + return json.Marshal(m) + } return []byte{}, nil } -// All possible requests that an agent can send to a client. This enum is used internally for routing RPC requests. You typically won't need to use this directly - instead, use the methods on the ['Client'] trait. This enum encompasses all method calls from agent to client. +// A message (request, response, or notification) with '"jsonrpc": "2.0"' specified as +// [required by JSON-RPC 2.0 Specification][1]. +// +// [1]: https://www.jsonrpc.org/specification#compatibility +type AgentOutgoingMessageRequest struct { + // JSON RPC Request Id + // + // An identifier established by the Client that MUST contain a String, Number, or NULL value if included. If it is not included it is assumed to be a notification. The value SHOULD normally not be Null [1] and Numbers SHOULD NOT contain fractional parts [2] + // + // The Server MUST reply with the same value in the Response object if included. This member is used to correlate the context between the two objects. + // + // [1] The use of Null as a value for the id member in a Request object is discouraged, because this specification uses a value of Null for Responses with an unknown id. Also, because JSON-RPC 1.0 uses an id value of Null for Notifications this could cause confusion in handling. + // + // [2] Fractional parts may be problematic, since many decimal fractions cannot be represented exactly as binary fractions. + Id any `json:"id"` + Method string `json:"method"` + Params *AgentRequest `json:"params,omitempty"` +} + +type AgentOutgoingMessageResponse struct { + // JSON RPC Request Id + // + // An identifier established by the Client that MUST contain a String, Number, or NULL value if included. If it is not included it is assumed to be a notification. The value SHOULD normally not be Null [1] and Numbers SHOULD NOT contain fractional parts [2] + // + // The Server MUST reply with the same value in the Response object if included. This member is used to correlate the context between the two objects. + // + // [1] The use of Null as a value for the id member in a Request object is discouraged, because this specification uses a value of Null for Responses with an unknown id. Also, because JSON-RPC 1.0 uses an id value of Null for Notifications this could cause confusion in handling. + // + // [2] Fractional parts may be problematic, since many decimal fractions cannot be represented exactly as binary fractions. + Id any `json:"id"` +} + +type AgentOutgoingMessageNotification struct { + Method string `json:"method"` + Params *AgentNotification `json:"params,omitempty"` +} + +type AgentOutgoingMessage struct { + Request *AgentOutgoingMessageRequest `json:"-"` + Response *AgentOutgoingMessageResponse `json:"-"` + Notification *AgentOutgoingMessageNotification `json:"-"` +} + +func (u *AgentOutgoingMessage) UnmarshalJSON(b []byte) error { + var m map[string]json.RawMessage + if err := json.Unmarshal(b, &m); err != nil { + return err + } + { + var v AgentOutgoingMessageRequest + var match bool = true + if _, ok := m["id"]; !ok { + match = false + } + if _, ok := m["method"]; !ok { + match = false + } + if match { + if json.Unmarshal(b, &v) != nil { + return errors.New("invalid variant payload") + } + u.Request = &v + return nil + } + } + { + var v AgentOutgoingMessageResponse + var match bool = true + if _, ok := m["id"]; !ok { + match = false + } + if match { + if json.Unmarshal(b, &v) != nil { + return errors.New("invalid variant payload") + } + u.Response = &v + return nil + } + } + { + var v AgentOutgoingMessageNotification + var match bool = true + if _, ok := m["method"]; !ok { + match = false + } + if match { + if json.Unmarshal(b, &v) != nil { + return errors.New("invalid variant payload") + } + u.Notification = &v + return nil + } + } + { + var v AgentOutgoingMessageRequest + if json.Unmarshal(b, &v) == nil { + u.Request = &v + return nil + } + } + { + var v AgentOutgoingMessageResponse + if json.Unmarshal(b, &v) == nil { + u.Response = &v + return nil + } + } + { + var v AgentOutgoingMessageNotification + if json.Unmarshal(b, &v) == nil { + u.Notification = &v + return nil + } + } + return nil +} +func (u AgentOutgoingMessage) MarshalJSON() ([]byte, error) { + if u.Request != nil { + var m map[string]any + _b, _e := json.Marshal(*u.Request) + if _e != nil { + return []byte{}, _e + } + if json.Unmarshal(_b, &m) != nil { + return []byte{}, errors.New("invalid variant payload") + } + return json.Marshal(m) + } + if u.Response != nil { + var m map[string]any + _b, _e := json.Marshal(*u.Response) + if _e != nil { + return []byte{}, _e + } + if json.Unmarshal(_b, &m) != nil { + return []byte{}, errors.New("invalid variant payload") + } + return json.Marshal(m) + } + if u.Notification != nil { + var m map[string]any + _b, _e := json.Marshal(*u.Notification) + if _e != nil { + return []byte{}, _e + } + if json.Unmarshal(_b, &m) != nil { + return []byte{}, errors.New("invalid variant payload") + } + return json.Marshal(m) + } + return []byte{}, nil +} + +// All possible requests that an agent can send to a client. +// +// This enum is used internally for routing RPC requests. You typically won't need +// to use this directly - instead, use the methods on the ['Client'] trait. +// +// This enum encompasses all method calls from agent to client. +// Handles extension method requests from the agent. +// +// Allows the Agent to send an arbitrary request that is not part of the ACP spec. +// Extension methods provide a way to add custom functionality while maintaining +// protocol compatibility. +// +// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) +type AgentExtMethodRequest = json.RawMessage + type AgentRequest struct { - // Writes content to a text file in the client's file system. Only available if the client advertises the 'fs.writeTextFile' capability. Allows the agent to create or modify files within the client's environment. See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client) + // Writes content to a text file in the client's file system. + // + // Only available if the client advertises the 'fs.writeTextFile' capability. + // Allows the agent to create or modify files within the client's environment. + // + // See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client) WriteTextFileRequest *WriteTextFileRequest `json:"-"` - // Reads content from a text file in the client's file system. Only available if the client advertises the 'fs.readTextFile' capability. Allows the agent to access file contents within the client's environment. See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client) + // Reads content from a text file in the client's file system. + // + // Only available if the client advertises the 'fs.readTextFile' capability. + // Allows the agent to access file contents within the client's environment. + // + // See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client) ReadTextFileRequest *ReadTextFileRequest `json:"-"` - // Requests permission from the user for a tool call operation. Called by the agent when it needs user authorization before executing a potentially sensitive operation. The client should present the options to the user and return their decision. If the client cancels the prompt turn via 'session/cancel', it MUST respond to this request with 'RequestPermissionOutcome::Cancelled'. See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission) + // Requests permission from the user for a tool call operation. + // + // Called by the agent when it needs user authorization before executing + // a potentially sensitive operation. The client should present the options + // to the user and return their decision. + // + // If the client cancels the prompt turn via 'session/cancel', it MUST + // respond to this request with 'RequestPermissionOutcome::Cancelled'. + // + // See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission) RequestPermissionRequest *RequestPermissionRequest `json:"-"` - // Executes a command in a new terminal Only available if the 'terminal' Client capability is set to 'true'. Returns a 'TerminalId' that can be used with other terminal methods to get the current output, wait for exit, and kill the command. The 'TerminalId' can also be used to embed the terminal in a tool call by using the 'ToolCallContent::Terminal' variant. The Agent is responsible for releasing the terminal by using the 'terminal/release' method. See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals) + // Executes a command in a new terminal + // + // Only available if the 'terminal' Client capability is set to 'true'. + // + // Returns a 'TerminalId' that can be used with other terminal methods + // to get the current output, wait for exit, and kill the command. + // + // The 'TerminalId' can also be used to embed the terminal in a tool call + // by using the 'ToolCallContent::Terminal' variant. + // + // The Agent is responsible for releasing the terminal by using the 'terminal/release' + // method. + // + // See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals) CreateTerminalRequest *CreateTerminalRequest `json:"-"` - // Gets the terminal output and exit status Returns the current content in the terminal without waiting for the command to exit. If the command has already exited, the exit status is included. See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals) + // Gets the terminal output and exit status + // + // Returns the current content in the terminal without waiting for the command to exit. + // If the command has already exited, the exit status is included. + // + // See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals) TerminalOutputRequest *TerminalOutputRequest `json:"-"` - // Releases a terminal The command is killed if it hasn't exited yet. Use 'terminal/wait_for_exit' to wait for the command to exit before releasing the terminal. After release, the 'TerminalId' can no longer be used with other 'terminal/*' methods, but tool calls that already contain it, continue to display its output. The 'terminal/kill' method can be used to terminate the command without releasing the terminal, allowing the Agent to call 'terminal/output' and other methods. See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals) + // Releases a terminal + // + // The command is killed if it hasn't exited yet. Use 'terminal/wait_for_exit' + // to wait for the command to exit before releasing the terminal. + // + // After release, the 'TerminalId' can no longer be used with other 'terminal/*' methods, + // but tool calls that already contain it, continue to display its output. + // + // The 'terminal/kill' method can be used to terminate the command without releasing + // the terminal, allowing the Agent to call 'terminal/output' and other methods. + // + // See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals) ReleaseTerminalRequest *ReleaseTerminalRequest `json:"-"` - // Waits for the terminal command to exit and return its exit status See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals) + // Waits for the terminal command to exit and return its exit status + // + // See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals) WaitForTerminalExitRequest *WaitForTerminalExitRequest `json:"-"` - // Kills the terminal command without releasing the terminal While 'terminal/release' will also kill the command, this method will keep the 'TerminalId' valid so it can be used with other methods. This method can be helpful when implementing command timeouts which terminate the command as soon as elapsed, and then get the final output so it can be sent to the model. Note: 'terminal/release' when 'TerminalId' is no longer needed. See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals) + // Kills the terminal command without releasing the terminal + // + // While 'terminal/release' will also kill the command, this method will keep + // the 'TerminalId' valid so it can be used with other methods. + // + // This method can be helpful when implementing command timeouts which terminate + // the command as soon as elapsed, and then get the final output so it can be sent + // to the model. + // + // Note: 'terminal/release' when 'TerminalId' is no longer needed. + // + // See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals) KillTerminalCommandRequest *KillTerminalCommandRequest `json:"-"` + // Handles extension method requests from the agent. + // + // Allows the Agent to send an arbitrary request that is not part of the ACP spec. + // Extension methods provide a way to add custom functionality while maintaining + // protocol compatibility. + // + // See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + ExtMethodRequest *AgentExtMethodRequest `json:"-"` } func (u *AgentRequest) UnmarshalJSON(b []byte) error { @@ -182,6 +473,13 @@ func (u *AgentRequest) UnmarshalJSON(b []byte) error { return nil } } + { + var v AgentExtMethodRequest + if json.Unmarshal(b, &v) == nil { + u.ExtMethodRequest = &v + return nil + } + } return nil } func (u AgentRequest) MarshalJSON() ([]byte, error) { @@ -273,10 +571,28 @@ func (u AgentRequest) MarshalJSON() ([]byte, error) { } return json.Marshal(m) } + if u.ExtMethodRequest != nil { + var m map[string]any + _b, _e := json.Marshal(*u.ExtMethodRequest) + if _e != nil { + return []byte{}, _e + } + if json.Unmarshal(_b, &m) != nil { + return []byte{}, errors.New("invalid variant payload") + } + return json.Marshal(m) + } return []byte{}, nil } -// All possible responses that an agent can send to a client. This enum is used internally for routing RPC responses. You typically won't need to use this directly - the responses are handled automatically by the connection. These are responses to the corresponding 'ClientRequest' variants. +// All possible responses that an agent can send to a client. +// +// This enum is used internally for routing RPC responses. You typically won't need +// to use this directly - the responses are handled automatically by the connection. +// +// These are responses to the corresponding 'ClientRequest' variants. +type AgentExtMethodResponse = json.RawMessage + type AgentResponse struct { InitializeResponse *InitializeResponse `json:"-"` AuthenticateResponse *AuthenticateResponse `json:"-"` @@ -285,6 +601,7 @@ type AgentResponse struct { SetSessionModeResponse *SetSessionModeResponse `json:"-"` PromptResponse *PromptResponse `json:"-"` SetSessionModelResponse *SetSessionModelResponse `json:"-"` + ExtMethodResponse *AgentExtMethodResponse `json:"-"` } func (u *AgentResponse) UnmarshalJSON(b []byte) error { @@ -341,6 +658,13 @@ func (u *AgentResponse) UnmarshalJSON(b []byte) error { return nil } } + { + var v AgentExtMethodResponse + if json.Unmarshal(b, &v) == nil { + u.ExtMethodResponse = &v + return nil + } + } return nil } func (u AgentResponse) MarshalJSON() ([]byte, error) { @@ -421,6 +745,17 @@ func (u AgentResponse) MarshalJSON() ([]byte, error) { } return json.Marshal(m) } + if u.ExtMethodResponse != nil { + var m map[string]any + _b, _e := json.Marshal(*u.ExtMethodResponse) + if _e != nil { + return []byte{}, _e + } + if json.Unmarshal(_b, &m) != nil { + return []byte{}, errors.New("invalid variant payload") + } + return json.Marshal(m) + } return []byte{}, nil } @@ -433,15 +768,6 @@ type Annotations struct { Priority *float64 `json:"priority,omitempty"` } -// Audio provided to or from an LLM. -type AudioContent struct { - // Extension point for implementations - Meta any `json:"_meta,omitempty"` - Annotations *Annotations `json:"annotations,omitempty"` - Data string `json:"data"` - MimeType string `json:"mimeType"` -} - // Describes an available authentication method. type AuthMethod struct { // Extension point for implementations @@ -457,11 +783,14 @@ type AuthMethod struct { // Unique identifier for an authentication method. type AuthMethodId string -// Request parameters for the authenticate method. Specifies which authentication method to use. +// Request parameters for the authenticate method. +// +// Specifies which authentication method to use. type AuthenticateRequest struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` - // The ID of the authentication method to use. Must be one of the methods advertised in the initialize response. + // The ID of the authentication method to use. + // Must be one of the methods advertised in the initialize response. MethodId AuthMethodId `json:"methodId"` } @@ -493,14 +822,14 @@ type AvailableCommand struct { // The input specification for a command. // All text that was typed after the command name is provided as input. -type UnstructuredCommandInput struct { +type AvailableCommandUnstructuredCommandInput struct { // A hint to display when the input hasn't been provided yet Hint string `json:"hint"` } type AvailableCommandInput struct { // All text that was typed after the command name is provided as input. - UnstructuredCommandInput *UnstructuredCommandInput `json:"-"` + UnstructuredCommandInput *AvailableCommandUnstructuredCommandInput `json:"-"` } func (u *AvailableCommandInput) UnmarshalJSON(b []byte) error { @@ -509,7 +838,7 @@ func (u *AvailableCommandInput) UnmarshalJSON(b []byte) error { return err } { - var v UnstructuredCommandInput + var v AvailableCommandUnstructuredCommandInput var match bool = true if _, ok := m["hint"]; !ok { match = false @@ -523,7 +852,7 @@ func (u *AvailableCommandInput) UnmarshalJSON(b []byte) error { } } { - var v UnstructuredCommandInput + var v AvailableCommandUnstructuredCommandInput if json.Unmarshal(b, &v) == nil { u.UnstructuredCommandInput = &v return nil @@ -555,7 +884,9 @@ type BlobResourceContents struct { Uri string `json:"uri"` } -// Notification to cancel ongoing operations for a session. See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation) +// Notification to cancel ongoing operations for a session. +// +// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation) type CancelNotification struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` @@ -567,11 +898,17 @@ func (v *CancelNotification) Validate() error { return nil } -// Capabilities supported by the client. Advertised during initialization to inform the agent about available features and methods. See protocol docs: [Client Capabilities](https://agentclientprotocol.com/protocol/initialization#client-capabilities) +// Capabilities supported by the client. +// +// Advertised during initialization to inform the agent about +// available features and methods. +// +// See protocol docs: [Client Capabilities](https://agentclientprotocol.com/protocol/initialization#client-capabilities) type ClientCapabilities struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` - // File system capabilities supported by the client. Determines which file operations the agent can request. + // File system capabilities supported by the client. + // Determines which file operations the agent can request. // // Defaults to {"readTextFile":false,"writeTextFile":false} if unset. Fs FileSystemCapability `json:"fs,omitempty"` @@ -605,39 +942,240 @@ func (v *ClientCapabilities) UnmarshalJSON(b []byte) error { } } { - _rm, _ok := m["terminal"] - if !_ok || (string(_rm) == "null") { - json.Unmarshal([]byte("false"), &a.Terminal) + _rm, _ok := m["terminal"] + if !_ok || (string(_rm) == "null") { + json.Unmarshal([]byte("false"), &a.Terminal) + } + } + *v = ClientCapabilities(a) + return nil +} + +// All possible notifications that a client can send to an agent. +// +// This enum is used internally for routing RPC notifications. You typically won't need +// to use this directly - use the notification methods on the ['Agent'] trait instead. +// +// Notifications do not expect a response. +// Handles extension notifications from the client. +// +// Extension notifications provide a way to send one-way messages for custom functionality +// while maintaining protocol compatibility. +// +// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) +type ClientExtNotification = json.RawMessage + +type ClientNotification struct { + // Cancels ongoing operations for a session. + // + // This is a notification sent by the client to cancel an ongoing prompt turn. + // + // Upon receiving this notification, the Agent SHOULD: + // - Stop all language model requests as soon as possible + // - Abort all tool call invocations in progress + // - Send any pending 'session/update' notifications + // - Respond to the original 'session/prompt' request with 'StopReason::Cancelled' + // + // See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation) + CancelNotification *CancelNotification `json:"-"` + // Handles extension notifications from the client. + // + // Extension notifications provide a way to send one-way messages for custom functionality + // while maintaining protocol compatibility. + // + // See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + ExtNotification *ClientExtNotification `json:"-"` +} + +func (u *ClientNotification) UnmarshalJSON(b []byte) error { + var m map[string]json.RawMessage + if err := json.Unmarshal(b, &m); err != nil { + return err + } + { + var v CancelNotification + if json.Unmarshal(b, &v) == nil { + u.CancelNotification = &v + return nil + } + } + { + var v ClientExtNotification + if json.Unmarshal(b, &v) == nil { + u.ExtNotification = &v + return nil + } + } + return nil +} +func (u ClientNotification) MarshalJSON() ([]byte, error) { + if u.CancelNotification != nil { + var m map[string]any + _b, _e := json.Marshal(*u.CancelNotification) + if _e != nil { + return []byte{}, _e + } + if json.Unmarshal(_b, &m) != nil { + return []byte{}, errors.New("invalid variant payload") + } + return json.Marshal(m) + } + if u.ExtNotification != nil { + var m map[string]any + _b, _e := json.Marshal(*u.ExtNotification) + if _e != nil { + return []byte{}, _e + } + if json.Unmarshal(_b, &m) != nil { + return []byte{}, errors.New("invalid variant payload") + } + return json.Marshal(m) + } + return []byte{}, nil +} + +// A message (request, response, or notification) with '"jsonrpc": "2.0"' specified as +// [required by JSON-RPC 2.0 Specification][1]. +// +// [1]: https://www.jsonrpc.org/specification#compatibility +type ClientOutgoingMessageRequest struct { + // JSON RPC Request Id + // + // An identifier established by the Client that MUST contain a String, Number, or NULL value if included. If it is not included it is assumed to be a notification. The value SHOULD normally not be Null [1] and Numbers SHOULD NOT contain fractional parts [2] + // + // The Server MUST reply with the same value in the Response object if included. This member is used to correlate the context between the two objects. + // + // [1] The use of Null as a value for the id member in a Request object is discouraged, because this specification uses a value of Null for Responses with an unknown id. Also, because JSON-RPC 1.0 uses an id value of Null for Notifications this could cause confusion in handling. + // + // [2] Fractional parts may be problematic, since many decimal fractions cannot be represented exactly as binary fractions. + Id any `json:"id"` + Method string `json:"method"` + Params *ClientRequest `json:"params,omitempty"` +} + +type ClientOutgoingMessageResponse struct { + // JSON RPC Request Id + // + // An identifier established by the Client that MUST contain a String, Number, or NULL value if included. If it is not included it is assumed to be a notification. The value SHOULD normally not be Null [1] and Numbers SHOULD NOT contain fractional parts [2] + // + // The Server MUST reply with the same value in the Response object if included. This member is used to correlate the context between the two objects. + // + // [1] The use of Null as a value for the id member in a Request object is discouraged, because this specification uses a value of Null for Responses with an unknown id. Also, because JSON-RPC 1.0 uses an id value of Null for Notifications this could cause confusion in handling. + // + // [2] Fractional parts may be problematic, since many decimal fractions cannot be represented exactly as binary fractions. + Id any `json:"id"` +} + +type ClientOutgoingMessageNotification struct { + Method string `json:"method"` + Params *ClientNotification `json:"params,omitempty"` +} + +type ClientOutgoingMessage struct { + Request *ClientOutgoingMessageRequest `json:"-"` + Response *ClientOutgoingMessageResponse `json:"-"` + Notification *ClientOutgoingMessageNotification `json:"-"` +} + +func (u *ClientOutgoingMessage) UnmarshalJSON(b []byte) error { + var m map[string]json.RawMessage + if err := json.Unmarshal(b, &m); err != nil { + return err + } + { + var v ClientOutgoingMessageRequest + var match bool = true + if _, ok := m["id"]; !ok { + match = false + } + if _, ok := m["method"]; !ok { + match = false + } + if match { + if json.Unmarshal(b, &v) != nil { + return errors.New("invalid variant payload") + } + u.Request = &v + return nil + } + } + { + var v ClientOutgoingMessageResponse + var match bool = true + if _, ok := m["id"]; !ok { + match = false + } + if match { + if json.Unmarshal(b, &v) != nil { + return errors.New("invalid variant payload") + } + u.Response = &v + return nil + } + } + { + var v ClientOutgoingMessageNotification + var match bool = true + if _, ok := m["method"]; !ok { + match = false + } + if match { + if json.Unmarshal(b, &v) != nil { + return errors.New("invalid variant payload") + } + u.Notification = &v + return nil + } + } + { + var v ClientOutgoingMessageRequest + if json.Unmarshal(b, &v) == nil { + u.Request = &v + return nil } } - *v = ClientCapabilities(a) - return nil -} - -// All possible notifications that a client can send to an agent. This enum is used internally for routing RPC notifications. You typically won't need to use this directly - use the notification methods on the ['Agent'] trait instead. Notifications do not expect a response. -type ClientNotification struct { - // Cancels ongoing operations for a session. This is a notification sent by the client to cancel an ongoing prompt turn. Upon receiving this notification, the Agent SHOULD: - Stop all language model requests as soon as possible - Abort all tool call invocations in progress - Send any pending 'session/update' notifications - Respond to the original 'session/prompt' request with 'StopReason::Cancelled' See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation) - CancelNotification *CancelNotification `json:"-"` -} - -func (u *ClientNotification) UnmarshalJSON(b []byte) error { - var m map[string]json.RawMessage - if err := json.Unmarshal(b, &m); err != nil { - return err + { + var v ClientOutgoingMessageResponse + if json.Unmarshal(b, &v) == nil { + u.Response = &v + return nil + } } { - var v CancelNotification + var v ClientOutgoingMessageNotification if json.Unmarshal(b, &v) == nil { - u.CancelNotification = &v + u.Notification = &v return nil } } return nil } -func (u ClientNotification) MarshalJSON() ([]byte, error) { - if u.CancelNotification != nil { +func (u ClientOutgoingMessage) MarshalJSON() ([]byte, error) { + if u.Request != nil { var m map[string]any - _b, _e := json.Marshal(*u.CancelNotification) + _b, _e := json.Marshal(*u.Request) + if _e != nil { + return []byte{}, _e + } + if json.Unmarshal(_b, &m) != nil { + return []byte{}, errors.New("invalid variant payload") + } + return json.Marshal(m) + } + if u.Response != nil { + var m map[string]any + _b, _e := json.Marshal(*u.Response) + if _e != nil { + return []byte{}, _e + } + if json.Unmarshal(_b, &m) != nil { + return []byte{}, errors.New("invalid variant payload") + } + return json.Marshal(m) + } + if u.Notification != nil { + var m map[string]any + _b, _e := json.Marshal(*u.Notification) if _e != nil { return []byte{}, _e } @@ -649,22 +1187,105 @@ func (u ClientNotification) MarshalJSON() ([]byte, error) { return []byte{}, nil } -// All possible requests that a client can send to an agent. This enum is used internally for routing RPC requests. You typically won't need to use this directly - instead, use the methods on the ['Agent'] trait. This enum encompasses all method calls from client to agent. +// All possible requests that a client can send to an agent. +// +// This enum is used internally for routing RPC requests. You typically won't need +// to use this directly - instead, use the methods on the ['Agent'] trait. +// +// This enum encompasses all method calls from client to agent. +// Handles extension method requests from the client. +// +// Extension methods provide a way to add custom functionality while maintaining +// protocol compatibility. +// +// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) +type ClientExtMethodRequest = json.RawMessage + type ClientRequest struct { - // Establishes the connection with a client and negotiates protocol capabilities. This method is called once at the beginning of the connection to: - Negotiate the protocol version to use - Exchange capability information between client and agent - Determine available authentication methods The agent should respond with its supported protocol version and capabilities. See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization) + // Establishes the connection with a client and negotiates protocol capabilities. + // + // This method is called once at the beginning of the connection to: + // - Negotiate the protocol version to use + // - Exchange capability information between client and agent + // - Determine available authentication methods + // + // The agent should respond with its supported protocol version and capabilities. + // + // See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization) InitializeRequest *InitializeRequest `json:"-"` - // Authenticates the client using the specified authentication method. Called when the agent requires authentication before allowing session creation. The client provides the authentication method ID that was advertised during initialization. After successful authentication, the client can proceed to create sessions with 'new_session' without receiving an 'auth_required' error. See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization) + // Authenticates the client using the specified authentication method. + // + // Called when the agent requires authentication before allowing session creation. + // The client provides the authentication method ID that was advertised during initialization. + // + // After successful authentication, the client can proceed to create sessions with + // 'new_session' without receiving an 'auth_required' error. + // + // See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization) AuthenticateRequest *AuthenticateRequest `json:"-"` - // Creates a new conversation session with the agent. Sessions represent independent conversation contexts with their own history and state. The agent should: - Create a new session context - Connect to any specified MCP servers - Return a unique session ID for future requests May return an 'auth_required' error if the agent requires authentication. See protocol docs: [Session Setup](https://agentclientprotocol.com/protocol/session-setup) + // Creates a new conversation session with the agent. + // + // Sessions represent independent conversation contexts with their own history and state. + // + // The agent should: + // - Create a new session context + // - Connect to any specified MCP servers + // - Return a unique session ID for future requests + // + // May return an 'auth_required' error if the agent requires authentication. + // + // See protocol docs: [Session Setup](https://agentclientprotocol.com/protocol/session-setup) NewSessionRequest *NewSessionRequest `json:"-"` - // Loads an existing session to resume a previous conversation. This method is only available if the agent advertises the 'loadSession' capability. The agent should: - Restore the session context and conversation history - Connect to the specified MCP servers - Stream the entire conversation history back to the client via notifications See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions) + // Loads an existing session to resume a previous conversation. + // + // This method is only available if the agent advertises the 'loadSession' capability. + // + // The agent should: + // - Restore the session context and conversation history + // - Connect to the specified MCP servers + // - Stream the entire conversation history back to the client via notifications + // + // See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions) LoadSessionRequest *LoadSessionRequest `json:"-"` - // Sets the current mode for a session. Allows switching between different agent modes (e.g., "ask", "architect", "code") that affect system prompts, tool availability, and permission behaviors. The mode must be one of the modes advertised in 'availableModes' during session creation or loading. Agents may also change modes autonomously and notify the client via 'current_mode_update' notifications. This method can be called at any time during a session, whether the Agent is idle or actively generating a response. See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) + // Sets the current mode for a session. + // + // Allows switching between different agent modes (e.g., "ask", "architect", "code") + // that affect system prompts, tool availability, and permission behaviors. + // + // The mode must be one of the modes advertised in 'availableModes' during session + // creation or loading. Agents may also change modes autonomously and notify the + // client via 'current_mode_update' notifications. + // + // This method can be called at any time during a session, whether the Agent is + // idle or actively generating a response. + // + // See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) SetSessionModeRequest *SetSessionModeRequest `json:"-"` - // Processes a user prompt within a session. This method handles the whole lifecycle of a prompt: - Receives user messages with optional context (files, images, etc.) - Processes the prompt using language models - Reports language model content and tool calls to the Clients - Requests permission to run tools - Executes any requested tool calls - Returns when the turn is complete with a stop reason See protocol docs: [Prompt Turn](https://agentclientprotocol.com/protocol/prompt-turn) + // Processes a user prompt within a session. + // + // This method handles the whole lifecycle of a prompt: + // - Receives user messages with optional context (files, images, etc.) + // - Processes the prompt using language models + // - Reports language model content and tool calls to the Clients + // - Requests permission to run tools + // - Executes any requested tool calls + // - Returns when the turn is complete with a stop reason + // + // See protocol docs: [Prompt Turn](https://agentclientprotocol.com/protocol/prompt-turn) PromptRequest *PromptRequest `json:"-"` - // **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. Select a model for a given session. + // **UNSTABLE** + // + // This capability is not part of the spec yet, and may be removed or changed at any point. + // + // Select a model for a given session. SetSessionModelRequest *SetSessionModelRequest `json:"-"` + // Handles extension method requests from the client. + // + // Extension methods provide a way to add custom functionality while maintaining + // protocol compatibility. + // + // See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + ExtMethodRequest *ClientExtMethodRequest `json:"-"` } func (u *ClientRequest) UnmarshalJSON(b []byte) error { @@ -721,6 +1342,13 @@ func (u *ClientRequest) UnmarshalJSON(b []byte) error { return nil } } + { + var v ClientExtMethodRequest + if json.Unmarshal(b, &v) == nil { + u.ExtMethodRequest = &v + return nil + } + } return nil } func (u ClientRequest) MarshalJSON() ([]byte, error) { @@ -801,10 +1429,28 @@ func (u ClientRequest) MarshalJSON() ([]byte, error) { } return json.Marshal(m) } + if u.ExtMethodRequest != nil { + var m map[string]any + _b, _e := json.Marshal(*u.ExtMethodRequest) + if _e != nil { + return []byte{}, _e + } + if json.Unmarshal(_b, &m) != nil { + return []byte{}, errors.New("invalid variant payload") + } + return json.Marshal(m) + } return []byte{}, nil } -// All possible responses that a client can send to an agent. This enum is used internally for routing RPC responses. You typically won't need to use this directly - the responses are handled automatically by the connection. These are responses to the corresponding 'AgentRequest' variants. +// All possible responses that a client can send to an agent. +// +// This enum is used internally for routing RPC responses. You typically won't need +// to use this directly - the responses are handled automatically by the connection. +// +// These are responses to the corresponding 'AgentRequest' variants. +type ClientExtMethodResponse = json.RawMessage + type ClientResponse struct { WriteTextFileResponse *WriteTextFileResponse `json:"-"` ReadTextFileResponse *ReadTextFileResponse `json:"-"` @@ -813,7 +1459,8 @@ type ClientResponse struct { TerminalOutputResponse *TerminalOutputResponse `json:"-"` ReleaseTerminalResponse *ReleaseTerminalResponse `json:"-"` WaitForTerminalExitResponse *WaitForTerminalExitResponse `json:"-"` - KillTerminalCommandResponse *KillTerminalCommandResponse `json:"-"` + KillTerminalResponse *KillTerminalCommandResponse `json:"-"` + ExtMethodResponse *ClientExtMethodResponse `json:"-"` } func (u *ClientResponse) UnmarshalJSON(b []byte) error { @@ -873,7 +1520,14 @@ func (u *ClientResponse) UnmarshalJSON(b []byte) error { { var v KillTerminalCommandResponse if json.Unmarshal(b, &v) == nil { - u.KillTerminalCommandResponse = &v + u.KillTerminalResponse = &v + return nil + } + } + { + var v ClientExtMethodResponse + if json.Unmarshal(b, &v) == nil { + u.ExtMethodResponse = &v return nil } } @@ -957,9 +1611,20 @@ func (u ClientResponse) MarshalJSON() ([]byte, error) { } return json.Marshal(m) } - if u.KillTerminalCommandResponse != nil { + if u.KillTerminalResponse != nil { + var m map[string]any + _b, _e := json.Marshal(*u.KillTerminalResponse) + if _e != nil { + return []byte{}, _e + } + if json.Unmarshal(_b, &m) != nil { + return []byte{}, errors.New("invalid variant payload") + } + return json.Marshal(m) + } + if u.ExtMethodResponse != nil { var m map[string]any - _b, _e := json.Marshal(*u.KillTerminalCommandResponse) + _b, _e := json.Marshal(*u.ExtMethodResponse) if _e != nil { return []byte{}, _e } @@ -971,8 +1636,24 @@ func (u ClientResponse) MarshalJSON() ([]byte, error) { return []byte{}, nil } -// Content blocks represent displayable information in the Agent Client Protocol. They provide a structured way to handle various types of user-facing content—whether it's text from language models, images for analysis, or embedded resources for context. Content blocks appear in: - User prompts sent via 'session/prompt' - Language model output streamed through 'session/update' notifications - Progress updates and results from tool calls This structure is compatible with the Model Context Protocol (MCP), enabling agents to seamlessly forward content from MCP tool outputs without transformation. See protocol docs: [Content](https://agentclientprotocol.com/protocol/content) -// Plain text content All agents MUST support text content blocks in prompts. +// Content blocks represent displayable information in the Agent Client Protocol. +// +// They provide a structured way to handle various types of user-facing content—whether +// it's text from language models, images for analysis, or embedded resources for context. +// +// Content blocks appear in: +// - User prompts sent via 'session/prompt' +// - Language model output streamed through 'session/update' notifications +// - Progress updates and results from tool calls +// +// This structure is compatible with the Model Context Protocol (MCP), enabling +// agents to seamlessly forward content from MCP tool outputs without transformation. +// +// See protocol docs: [Content](https://agentclientprotocol.com/protocol/content) +// Text content. May be plain text or formatted with Markdown. +// +// All agents MUST support text content blocks in prompts. +// Clients SHOULD render this text as Markdown. type ContentBlockText struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` @@ -981,7 +1662,9 @@ type ContentBlockText struct { Type string `json:"type"` } -// Images for visual context or analysis. Requires the 'image' prompt capability when included in prompts. +// Images for visual context or analysis. +// +// Requires the 'image' prompt capability when included in prompts. type ContentBlockImage struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` @@ -992,7 +1675,9 @@ type ContentBlockImage struct { Uri *string `json:"uri,omitempty"` } -// Audio data for transcription or analysis. Requires the 'audio' prompt capability when included in prompts. +// Audio data for transcription or analysis. +// +// Requires the 'audio' prompt capability when included in prompts. type ContentBlockAudio struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` @@ -1002,7 +1687,9 @@ type ContentBlockAudio struct { Type string `json:"type"` } -// References to resources that the agent can access. All agents MUST support resource links in prompts. +// References to resources that the agent can access. +// +// All agents MUST support resource links in prompts. type ContentBlockResourceLink struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` @@ -1016,7 +1703,11 @@ type ContentBlockResourceLink struct { Uri string `json:"uri"` } -// Complete resource contents embedded directly in the message. Preferred for including context as it avoids extra round-trips. Requires the 'embeddedContext' prompt capability when included in prompts. +// Complete resource contents embedded directly in the message. +// +// Preferred for including context as it avoids extra round-trips. +// +// Requires the 'embeddedContext' prompt capability when included in prompts. type ContentBlockResource struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` @@ -1026,15 +1717,28 @@ type ContentBlockResource struct { } type ContentBlock struct { - // Plain text content All agents MUST support text content blocks in prompts. + // Text content. May be plain text or formatted with Markdown. + // + // All agents MUST support text content blocks in prompts. + // Clients SHOULD render this text as Markdown. Text *ContentBlockText `json:"-"` - // Images for visual context or analysis. Requires the 'image' prompt capability when included in prompts. + // Images for visual context or analysis. + // + // Requires the 'image' prompt capability when included in prompts. Image *ContentBlockImage `json:"-"` - // Audio data for transcription or analysis. Requires the 'audio' prompt capability when included in prompts. + // Audio data for transcription or analysis. + // + // Requires the 'audio' prompt capability when included in prompts. Audio *ContentBlockAudio `json:"-"` - // References to resources that the agent can access. All agents MUST support resource links in prompts. + // References to resources that the agent can access. + // + // All agents MUST support resource links in prompts. ResourceLink *ContentBlockResourceLink `json:"-"` - // Complete resource contents embedded directly in the message. Preferred for including context as it avoids extra round-trips. Requires the 'embeddedContext' prompt capability when included in prompts. + // Complete resource contents embedded directly in the message. + // + // Preferred for including context as it avoids extra round-trips. + // + // Requires the 'embeddedContext' prompt capability when included in prompts. Resource *ContentBlockResource `json:"-"` } @@ -1364,7 +2068,14 @@ type CreateTerminalRequest struct { Cwd *string `json:"cwd,omitempty"` // Environment variables for the command. Env []EnvVariable `json:"env,omitempty"` - // Maximum number of output bytes to retain. When the limit is exceeded, the Client truncates from the beginning of the output to stay within the limit. The Client MUST ensure truncation happens at a character boundary to maintain valid string output, even if this means the retained output is slightly less than the specified limit. + // Maximum number of output bytes to retain. + // + // When the limit is exceeded, the Client truncates from the beginning of the output + // to stay within the limit. + // + // The Client MUST ensure truncation happens at a character boundary to maintain valid + // string output, even if this means the retained output is slightly less than the + // specified limit. OutputByteLimit *int `json:"outputByteLimit,omitempty"` // The session ID for this request. SessionId SessionId `json:"sessionId"` @@ -1392,14 +2103,6 @@ func (v *CreateTerminalResponse) Validate() error { return nil } -// The contents of a resource, embedded into a prompt or tool call result. -type EmbeddedResource struct { - // Extension point for implementations - Meta any `json:"_meta,omitempty"` - Annotations *Annotations `json:"annotations,omitempty"` - Resource EmbeddedResourceResource `json:"resource"` -} - // Resource content that can be embedded in a message. type EmbeddedResourceResource struct { TextResourceContents *TextResourceContents `json:"-"` @@ -1479,7 +2182,27 @@ type EnvVariable struct { Value string `json:"value"` } -// File system capabilities that a client may support. See protocol docs: [FileSystem](https://agentclientprotocol.com/protocol/initialization#filesystem) +// JSON-RPC error object. +// +// Represents an error that occurred during method execution, following the +// JSON-RPC 2.0 error object specification with optional additional data. +// +// See protocol docs: [JSON-RPC Error Object](https://www.jsonrpc.org/specification#error_object) +type Error struct { + // A number indicating the error type that occurred. + // This must be an integer as defined in the JSON-RPC specification. + Code int `json:"code"` + // Optional primitive or structured value that contains additional information about the error. + // This may include debugging information or context-specific details. + Data any `json:"data,omitempty"` + // A string providing a short description of the error. + // The message should be limited to a concise single sentence. + Message string `json:"message"` +} + +// File system capabilities that a client may support. +// +// See protocol docs: [FileSystem](https://agentclientprotocol.com/protocol/initialization#filesystem) type FileSystemCapability struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` @@ -1536,17 +2259,27 @@ type HttpHeader struct { Value string `json:"value"` } -// An image provided to or from an LLM. -type ImageContent struct { - // Extension point for implementations - Meta any `json:"_meta,omitempty"` - Annotations *Annotations `json:"annotations,omitempty"` - Data string `json:"data"` - MimeType string `json:"mimeType"` - Uri *string `json:"uri,omitempty"` +// Describes the name and version of an MCP implementation, with an optional +// title for UI representation. +type Implementation struct { + // Intended for programmatic or logical use, but can be used as a display + // name fallback if title isn’t present. + Name string `json:"name"` + // Intended for UI and end-user contexts — optimized to be human-readable + // and easily understood. + // + // If not provided, the name should be used for display. + Title *string `json:"title,omitempty"` + // Version of the implementation. Can be displayed to the user or used + // for debugging or metrics purposes. + Version string `json:"version"` } -// Request parameters for the initialize method. Sent by the client to establish connection and negotiate capabilities. See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization) +// Request parameters for the initialize method. +// +// Sent by the client to establish connection and negotiate capabilities. +// +// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization) type InitializeRequest struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` @@ -1554,6 +2287,10 @@ type InitializeRequest struct { // // Defaults to {"fs":{"readTextFile":false,"writeTextFile":false},"terminal":false} if unset. ClientCapabilities ClientCapabilities `json:"clientCapabilities,omitempty"` + // Information about the Client name and version sent to the Agent. + // + // Note: in future versions of the protocol, this will be required. + ClientInfo *Implementation `json:"clientInfo,omitempty"` // The latest protocol version supported by the client. ProtocolVersion ProtocolVersion `json:"protocolVersion"` } @@ -1589,7 +2326,11 @@ func (v *InitializeRequest) Validate() error { return nil } -// Response from the initialize method. Contains the negotiated protocol version and agent capabilities. See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization) +// Response from the initialize method. +// +// Contains the negotiated protocol version and agent capabilities. +// +// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization) type InitializeResponse struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` @@ -1597,11 +2338,18 @@ type InitializeResponse struct { // // Defaults to {"loadSession":false,"mcpCapabilities":{"http":false,"sse":false},"promptCapabilities":{"audio":false,"embeddedContext":false,"image":false}} if unset. AgentCapabilities AgentCapabilities `json:"agentCapabilities,omitempty"` + // Information about the Agent name and version sent to the Client. + // + // Note: in future versions of the protocol, this will be required. + AgentInfo *Implementation `json:"agentInfo,omitempty"` // Authentication methods supported by the agent. // // Defaults to [] if unset. AuthMethods []AuthMethod `json:"authMethods"` - // The protocol version the client specified if supported by the agent, or the latest protocol version supported by the agent. The client should disconnect, if it doesn't support this version. + // The protocol version the client specified if supported by the agent, + // or the latest protocol version supported by the agent. + // + // The client should disconnect, if it doesn't support this version. ProtocolVersion ProtocolVersion `json:"protocolVersion"` } @@ -1672,7 +2420,11 @@ func (v *KillTerminalCommandResponse) Validate() error { return nil } -// Request parameters for loading an existing session. Only available if the Agent supports the 'loadSession' capability. See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions) +// Request parameters for loading an existing session. +// +// Only available if the Agent supports the 'loadSession' capability. +// +// See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions) type LoadSessionRequest struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` @@ -1698,9 +2450,15 @@ func (v *LoadSessionRequest) Validate() error { type LoadSessionResponse struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` - // **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. Initial model state if supported by the Agent + // **UNSTABLE** + // + // This capability is not part of the spec yet, and may be removed or changed at any point. + // + // Initial model state if supported by the Agent Models *SessionModelState `json:"models,omitempty"` - // Initial mode state if supported by the Agent See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) + // Initial mode state if supported by the Agent + // + // See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) Modes *SessionModeState `json:"modes,omitempty"` } @@ -1755,8 +2513,15 @@ func (v *McpCapabilities) UnmarshalJSON(b []byte) error { return nil } -// Configuration for connecting to an MCP (Model Context Protocol) server. MCP servers provide tools and context that the agent can use when processing prompts. See protocol docs: [MCP Servers](https://agentclientprotocol.com/protocol/session-setup#mcp-servers) -// HTTP transport configuration Only available when the Agent capabilities indicate 'mcp_capabilities.http' is 'true'. +// Configuration for connecting to an MCP (Model Context Protocol) server. +// +// MCP servers provide tools and context that the agent can use when +// processing prompts. +// +// See protocol docs: [MCP Servers](https://agentclientprotocol.com/protocol/session-setup#mcp-servers) +// HTTP transport configuration +// +// Only available when the Agent capabilities indicate 'mcp_capabilities.http' is 'true'. type McpServerHttp struct { // HTTP headers to set when making requests to the MCP server. Headers []HttpHeader `json:"headers"` @@ -1767,7 +2532,9 @@ type McpServerHttp struct { Url string `json:"url"` } -// SSE transport configuration Only available when the Agent capabilities indicate 'mcp_capabilities.sse' is 'true'. +// SSE transport configuration +// +// Only available when the Agent capabilities indicate 'mcp_capabilities.sse' is 'true'. type McpServerSse struct { // HTTP headers to set when making requests to the MCP server. Headers []HttpHeader `json:"headers"` @@ -1778,8 +2545,10 @@ type McpServerSse struct { Url string `json:"url"` } -// Stdio transport configuration All Agents MUST support this transport. -type Stdio struct { +// Stdio transport configuration +// +// All Agents MUST support this transport. +type McpServerStdio struct { // Command-line arguments to pass to the MCP server. Args []string `json:"args"` // Path to the MCP server executable. @@ -1791,12 +2560,18 @@ type Stdio struct { } type McpServer struct { - // HTTP transport configuration Only available when the Agent capabilities indicate 'mcp_capabilities.http' is 'true'. + // HTTP transport configuration + // + // Only available when the Agent capabilities indicate 'mcp_capabilities.http' is 'true'. Http *McpServerHttp `json:"-"` - // SSE transport configuration Only available when the Agent capabilities indicate 'mcp_capabilities.sse' is 'true'. + // SSE transport configuration + // + // Only available when the Agent capabilities indicate 'mcp_capabilities.sse' is 'true'. Sse *McpServerSse `json:"-"` - // Stdio transport configuration All Agents MUST support this transport. - Stdio *Stdio `json:"-"` + // Stdio transport configuration + // + // All Agents MUST support this transport. + Stdio *McpServerStdio `json:"-"` } func (u *McpServer) UnmarshalJSON(b []byte) error { @@ -1873,7 +2648,7 @@ func (u *McpServer) UnmarshalJSON(b []byte) error { } } { - var v Stdio + var v McpServerStdio var match bool = true if _, ok := m["name"]; !ok { match = false @@ -1910,7 +2685,7 @@ func (u *McpServer) UnmarshalJSON(b []byte) error { } } { - var v Stdio + var v McpServerStdio if json.Unmarshal(b, &v) == nil { u.Stdio = &v return nil @@ -1957,10 +2732,18 @@ func (u McpServer) MarshalJSON() ([]byte, error) { return []byte{}, nil } -// **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. A unique identifier for a model. +// **UNSTABLE** +// +// This capability is not part of the spec yet, and may be removed or changed at any point. +// +// A unique identifier for a model. type ModelId string -// **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. Information about a selectable model. +// **UNSTABLE** +// +// This capability is not part of the spec yet, and may be removed or changed at any point. +// +// Information about a selectable model. type ModelInfo struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` @@ -1972,7 +2755,9 @@ type ModelInfo struct { Name string `json:"name"` } -// Request parameters for creating a new session. See protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol/session-setup#creating-a-session) +// Request parameters for creating a new session. +// +// See protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol/session-setup#creating-a-session) type NewSessionRequest struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` @@ -1992,15 +2777,25 @@ func (v *NewSessionRequest) Validate() error { return nil } -// Response from creating a new session. See protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol/session-setup#creating-a-session) +// Response from creating a new session. +// +// See protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol/session-setup#creating-a-session) type NewSessionResponse struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` - // **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. Initial model state if supported by the Agent + // **UNSTABLE** + // + // This capability is not part of the spec yet, and may be removed or changed at any point. + // + // Initial model state if supported by the Agent Models *SessionModelState `json:"models,omitempty"` - // Initial mode state if supported by the Agent See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) + // Initial mode state if supported by the Agent + // + // See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) Modes *SessionModeState `json:"modes,omitempty"` - // Unique identifier for the created session. Used in all subsequent requests for this conversation. + // Unique identifier for the created session. + // + // Used in all subsequent requests for this conversation. SessionId SessionId `json:"sessionId"` } @@ -2023,7 +2818,9 @@ type PermissionOption struct { // Unique identifier for a permission option. type PermissionOptionId string -// The type of permission option being presented to the user. Helps clients choose appropriate icons and UI treatment. +// The type of permission option being presented to the user. +// +// Helps clients choose appropriate icons and UI treatment. type PermissionOptionKind string const ( @@ -2033,27 +2830,28 @@ const ( PermissionOptionKindRejectAlways PermissionOptionKind = "reject_always" ) -// An execution plan for accomplishing complex tasks. Plans consist of multiple entries representing individual tasks or goals. Agents report plans to clients to provide visibility into their execution strategy. Plans can evolve during execution as the agent discovers new requirements or completes tasks. See protocol docs: [Agent Plan](https://agentclientprotocol.com/protocol/agent-plan) -type Plan struct { - // Extension point for implementations - Meta any `json:"_meta,omitempty"` - // The list of tasks to be accomplished. When updating a plan, the agent must send a complete list of all entries with their current status. The client replaces the entire plan with each update. - Entries []PlanEntry `json:"entries"` -} - -// A single entry in the execution plan. Represents a task or goal that the assistant intends to accomplish as part of fulfilling the user's request. See protocol docs: [Plan Entries](https://agentclientprotocol.com/protocol/agent-plan#plan-entries) +// A single entry in the execution plan. +// +// Represents a task or goal that the assistant intends to accomplish +// as part of fulfilling the user's request. +// See protocol docs: [Plan Entries](https://agentclientprotocol.com/protocol/agent-plan#plan-entries) type PlanEntry struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` // Human-readable description of what this task aims to accomplish. Content string `json:"content"` - // The relative importance of this task. Used to indicate which tasks are most critical to the overall goal. + // The relative importance of this task. + // Used to indicate which tasks are most critical to the overall goal. Priority PlanEntryPriority `json:"priority"` // Current execution status of this task. Status PlanEntryStatus `json:"status"` } -// Priority levels for plan entries. Used to indicate the relative importance or urgency of different tasks in the execution plan. See protocol docs: [Plan Entries](https://agentclientprotocol.com/protocol/agent-plan#plan-entries) +// Priority levels for plan entries. +// +// Used to indicate the relative importance or urgency of different +// tasks in the execution plan. +// See protocol docs: [Plan Entries](https://agentclientprotocol.com/protocol/agent-plan#plan-entries) type PlanEntryPriority string const ( @@ -2062,7 +2860,10 @@ const ( PlanEntryPriorityLow PlanEntryPriority = "low" ) -// Status of a plan entry in the execution flow. Tracks the lifecycle of each task from planning through completion. See protocol docs: [Plan Entries](https://agentclientprotocol.com/protocol/agent-plan#plan-entries) +// Status of a plan entry in the execution flow. +// +// Tracks the lifecycle of each task from planning through completion. +// See protocol docs: [Plan Entries](https://agentclientprotocol.com/protocol/agent-plan#plan-entries) type PlanEntryStatus string const ( @@ -2071,7 +2872,18 @@ const ( PlanEntryStatusCompleted PlanEntryStatus = "completed" ) -// Prompt capabilities supported by the agent in 'session/prompt' requests. Baseline agent functionality requires support for ['ContentBlock::Text'] and ['ContentBlock::ResourceLink'] in prompt requests. Other variants must be explicitly opted in to. Capabilities for different types of content in prompt requests. Indicates which content types beyond the baseline (text and resource links) the agent can process. See protocol docs: [Prompt Capabilities](https://agentclientprotocol.com/protocol/initialization#prompt-capabilities) +// Prompt capabilities supported by the agent in 'session/prompt' requests. +// +// Baseline agent functionality requires support for ['ContentBlock::Text'] +// and ['ContentBlock::ResourceLink'] in prompt requests. +// +// Other variants must be explicitly opted in to. +// Capabilities for different types of content in prompt requests. +// +// Indicates which content types beyond the baseline (text and resource links) +// the agent can process. +// +// See protocol docs: [Prompt Capabilities](https://agentclientprotocol.com/protocol/initialization#prompt-capabilities) type PromptCapabilities struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` @@ -2079,7 +2891,10 @@ type PromptCapabilities struct { // // Defaults to false if unset. Audio bool `json:"audio,omitempty"` - // Agent supports embedded context in 'session/prompt' requests. When enabled, the Client is allowed to include ['ContentBlock::Resource'] in prompt requests for pieces of context that are referenced in the message. + // Agent supports embedded context in 'session/prompt' requests. + // + // When enabled, the Client is allowed to include ['ContentBlock::Resource'] + // in prompt requests for pieces of context that are referenced in the message. // // Defaults to false if unset. EmbeddedContext bool `json:"embeddedContext,omitempty"` @@ -2128,11 +2943,27 @@ func (v *PromptCapabilities) UnmarshalJSON(b []byte) error { return nil } -// Request parameters for sending a user prompt to the agent. Contains the user's message and any additional context. See protocol docs: [User Message](https://agentclientprotocol.com/protocol/prompt-turn#1-user-message) +// Request parameters for sending a user prompt to the agent. +// +// Contains the user's message and any additional context. +// +// See protocol docs: [User Message](https://agentclientprotocol.com/protocol/prompt-turn#1-user-message) type PromptRequest struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` - // The blocks of content that compose the user's message. As a baseline, the Agent MUST support ['ContentBlock::Text'] and ['ContentBlock::ResourceLink'], while other variants are optionally enabled via ['PromptCapabilities']. The Client MUST adapt its interface according to ['PromptCapabilities']. The client MAY include referenced pieces of context as either ['ContentBlock::Resource'] or ['ContentBlock::ResourceLink']. When available, ['ContentBlock::Resource'] is preferred as it avoids extra round-trips and allows the message to include pieces of context from sources the agent may not have access to. + // The blocks of content that compose the user's message. + // + // As a baseline, the Agent MUST support ['ContentBlock::Text'] and ['ContentBlock::ResourceLink'], + // while other variants are optionally enabled via ['PromptCapabilities']. + // + // The Client MUST adapt its interface according to ['PromptCapabilities']. + // + // The client MAY include referenced pieces of context as either + // ['ContentBlock::Resource'] or ['ContentBlock::ResourceLink']. + // + // When available, ['ContentBlock::Resource'] is preferred + // as it avoids extra round-trips and allows the message to include + // pieces of context from sources the agent may not have access to. Prompt []ContentBlock `json:"prompt"` // The ID of the session to send this user message to SessionId SessionId `json:"sessionId"` @@ -2145,7 +2976,9 @@ func (v *PromptRequest) Validate() error { return nil } -// Response from processing a user prompt. See protocol docs: [Check for Completion](https://agentclientprotocol.com/protocol/prompt-turn#4-check-for-completion) +// Response from processing a user prompt. +// +// See protocol docs: [Check for Completion](https://agentclientprotocol.com/protocol/prompt-turn#4-check-for-completion) type PromptResponse struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` @@ -2157,10 +2990,15 @@ func (v *PromptResponse) Validate() error { return nil } -// Protocol version identifier. This version is only bumped for breaking changes. Non-breaking changes should be introduced via capabilities. +// Protocol version identifier. +// +// This version is only bumped for breaking changes. +// Non-breaking changes should be introduced via capabilities. type ProtocolVersion int -// Request to read content from a text file. Only available if the client supports the 'fs.readTextFile' capability. +// Request to read content from a text file. +// +// Only available if the client supports the 'fs.readTextFile' capability. type ReadTextFileRequest struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` @@ -2223,7 +3061,13 @@ func (v *ReleaseTerminalResponse) Validate() error { } // The outcome of a permission request. -// The prompt turn was cancelled before the user responded. When a client sends a 'session/cancel' notification to cancel an ongoing prompt turn, it MUST respond to all pending 'session/request_permission' requests with this 'Cancelled' outcome. See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation) +// The prompt turn was cancelled before the user responded. +// +// When a client sends a 'session/cancel' notification to cancel an ongoing +// prompt turn, it MUST respond to all pending 'session/request_permission' +// requests with this 'Cancelled' outcome. +// +// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation) type RequestPermissionOutcomeCancelled struct { Outcome string `json:"outcome"` } @@ -2236,7 +3080,13 @@ type RequestPermissionOutcomeSelected struct { } type RequestPermissionOutcome struct { - // The prompt turn was cancelled before the user responded. When a client sends a 'session/cancel' notification to cancel an ongoing prompt turn, it MUST respond to all pending 'session/request_permission' requests with this 'Cancelled' outcome. See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation) + // The prompt turn was cancelled before the user responded. + // + // When a client sends a 'session/cancel' notification to cancel an ongoing + // prompt turn, it MUST respond to all pending 'session/request_permission' + // requests with this 'Cancelled' outcome. + // + // See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation) Cancelled *RequestPermissionOutcomeCancelled `json:"-"` // The user selected one of the provided options. Selected *RequestPermissionOutcomeSelected `json:"-"` @@ -2358,7 +3208,33 @@ func (u *RequestPermissionOutcome) Validate() error { return nil } -// Request for user permission to execute a tool call. Sent when the agent needs authorization before performing a sensitive operation. See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission) +// Request for user permission to execute a tool call. +// +// Sent when the agent needs authorization before performing a sensitive operation. +// +// See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission) +// Details about the tool call requiring permission. +type RequestPermissionToolCall struct { + // Extension point for implementations + Meta any `json:"_meta,omitempty"` + // Replace the content collection. + Content []ToolCallContent `json:"content,omitempty"` + // Update the tool kind. + Kind *ToolKind `json:"kind,omitempty"` + // Replace the locations collection. + Locations []ToolCallLocation `json:"locations,omitempty"` + // Update the raw input. + RawInput any `json:"rawInput,omitempty"` + // Update the raw output. + RawOutput any `json:"rawOutput,omitempty"` + // Update the execution status. + Status *ToolCallStatus `json:"status,omitempty"` + // Update the human-readable title. + Title *string `json:"title,omitempty"` + // The ID of the tool call being updated. + ToolCallId ToolCallId `json:"toolCallId"` +} + type RequestPermissionRequest struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` @@ -2367,7 +3243,7 @@ type RequestPermissionRequest struct { // The session ID for this request. SessionId SessionId `json:"sessionId"` // Details about the tool call requiring permission. - ToolCall ToolCallUpdate `json:"toolCall"` + ToolCall RequestPermissionToolCall `json:"toolCall"` } func (v *RequestPermissionRequest) Validate() error { @@ -2389,19 +3265,6 @@ func (v *RequestPermissionResponse) Validate() error { return nil } -// A resource that the server is capable of reading, included in a prompt or tool call result. -type ResourceLink struct { - // Extension point for implementations - Meta any `json:"_meta,omitempty"` - Annotations *Annotations `json:"annotations,omitempty"` - Description *string `json:"description,omitempty"` - MimeType *string `json:"mimeType,omitempty"` - Name string `json:"name"` - Size *int `json:"size,omitempty"` - Title *string `json:"title,omitempty"` - Uri string `json:"uri"` -} - // The sender or recipient of messages and data in a conversation. type Role string @@ -2410,10 +3273,26 @@ const ( RoleUser Role = "user" ) -// A unique identifier for a conversation session between a client and agent. Sessions maintain their own context, conversation history, and state, allowing multiple independent interactions with the same agent. # Example ”' use agent_client_protocol::SessionId; use std::sync::Arc; let session_id = SessionId(Arc::from("sess_abc123def456")); ”' See protocol docs: [Session ID](https://agentclientprotocol.com/protocol/session-setup#session-id) +// A unique identifier for a conversation session between a client and agent. +// +// Sessions maintain their own context, conversation history, and state, +// allowing multiple independent interactions with the same agent. +// +// # Example +// +// ”' +// use agent_client_protocol::SessionId; +// use std::sync::Arc; +// +// let session_id = SessionId(Arc::from("sess_abc123def456")); +// ”' +// +// See protocol docs: [Session ID](https://agentclientprotocol.com/protocol/session-setup#session-id) type SessionId string -// A mode the agent can operate in. See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) +// A mode the agent can operate in. +// +// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) type SessionMode struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` @@ -2435,7 +3314,11 @@ type SessionModeState struct { CurrentModeId SessionModeId `json:"currentModeId"` } -// **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. The set of models and the one currently active. +// **UNSTABLE** +// +// This capability is not part of the spec yet, and may be removed or changed at any point. +// +// The set of models and the one currently active. type SessionModelState struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` @@ -2445,7 +3328,11 @@ type SessionModelState struct { CurrentModelId ModelId `json:"currentModelId"` } -// Notification containing a session update from the agent. Used to stream real-time progress and results during prompt processing. See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output) +// Notification containing a session update from the agent. +// +// Used to stream real-time progress and results during prompt processing. +// +// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output) type SessionNotification struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` @@ -2459,21 +3346,34 @@ func (v *SessionNotification) Validate() error { return nil } -// Different types of updates that can be sent during session processing. These updates provide real-time feedback about the agent's progress. See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output) +// Different types of updates that can be sent during session processing. +// +// These updates provide real-time feedback about the agent's progress. +// +// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output) // A chunk of the user's message being streamed. type SessionUpdateUserMessageChunk struct { + // Extension point for implementations + Meta any `json:"_meta,omitempty"` + // A single item of content Content ContentBlock `json:"content"` SessionUpdate string `json:"sessionUpdate"` } // A chunk of the agent's response being streamed. type SessionUpdateAgentMessageChunk struct { + // Extension point for implementations + Meta any `json:"_meta,omitempty"` + // A single item of content Content ContentBlock `json:"content"` SessionUpdate string `json:"sessionUpdate"` } // A chunk of the agent's internal reasoning being streamed. type SessionUpdateAgentThoughtChunk struct { + // Extension point for implementations + Meta any `json:"_meta,omitempty"` + // A single item of content Content ContentBlock `json:"content"` SessionUpdate string `json:"sessionUpdate"` } @@ -2484,9 +3384,11 @@ type SessionUpdateToolCall struct { Meta any `json:"_meta,omitempty"` // Content produced by the tool call. Content []ToolCallContent `json:"content,omitempty"` - // The category of tool being invoked. Helps clients choose appropriate icons and UI treatment. + // The category of tool being invoked. + // Helps clients choose appropriate icons and UI treatment. Kind ToolKind `json:"kind,omitempty"` - // File locations affected by this tool call. Enables "follow-along" features in clients. + // File locations affected by this tool call. + // Enables "follow-along" features in clients. Locations []ToolCallLocation `json:"locations,omitempty"` // Raw input parameters sent to the tool. RawInput any `json:"rawInput,omitempty"` @@ -2502,7 +3404,7 @@ type SessionUpdateToolCall struct { } // Update on the status or results of a tool call. -type SessionUpdateToolCallUpdate struct { +type SessionToolCallUpdate struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` // Replace the content collection. @@ -2524,23 +3426,35 @@ type SessionUpdateToolCallUpdate struct { ToolCallId ToolCallId `json:"toolCallId"` } -// The agent's execution plan for complex tasks. See protocol docs: [Agent Plan](https://agentclientprotocol.com/protocol/agent-plan) +// The agent's execution plan for complex tasks. +// See protocol docs: [Agent Plan](https://agentclientprotocol.com/protocol/agent-plan) type SessionUpdatePlan struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` - // The list of tasks to be accomplished. When updating a plan, the agent must send a complete list of all entries with their current status. The client replaces the entire plan with each update. + // The list of tasks to be accomplished. + // + // When updating a plan, the agent must send a complete list of all entries + // with their current status. The client replaces the entire plan with each update. Entries []PlanEntry `json:"entries"` SessionUpdate string `json:"sessionUpdate"` } // Available commands are ready or have changed -type SessionUpdateAvailableCommandsUpdate struct { +type SessionAvailableCommandsUpdate struct { + // Extension point for implementations + Meta any `json:"_meta,omitempty"` + // Commands the agent can execute AvailableCommands []AvailableCommand `json:"availableCommands"` SessionUpdate string `json:"sessionUpdate"` } -// The current mode of the session has changed See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) -type SessionUpdateCurrentModeUpdate struct { +// The current mode of the session has changed +// +// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) +type SessionCurrentModeUpdate struct { + // Extension point for implementations + Meta any `json:"_meta,omitempty"` + // The ID of the current mode CurrentModeId SessionModeId `json:"currentModeId"` SessionUpdate string `json:"sessionUpdate"` } @@ -2555,13 +3469,16 @@ type SessionUpdate struct { // Notification that a new tool call has been initiated. ToolCall *SessionUpdateToolCall `json:"-"` // Update on the status or results of a tool call. - ToolCallUpdate *SessionUpdateToolCallUpdate `json:"-"` - // The agent's execution plan for complex tasks. See protocol docs: [Agent Plan](https://agentclientprotocol.com/protocol/agent-plan) + ToolCallUpdate *SessionToolCallUpdate `json:"-"` + // The agent's execution plan for complex tasks. + // See protocol docs: [Agent Plan](https://agentclientprotocol.com/protocol/agent-plan) Plan *SessionUpdatePlan `json:"-"` // Available commands are ready or have changed - AvailableCommandsUpdate *SessionUpdateAvailableCommandsUpdate `json:"-"` - // The current mode of the session has changed See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) - CurrentModeUpdate *SessionUpdateCurrentModeUpdate `json:"-"` + AvailableCommandsUpdate *SessionAvailableCommandsUpdate `json:"-"` + // The current mode of the session has changed + // + // See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes) + CurrentModeUpdate *SessionCurrentModeUpdate `json:"-"` } func (u *SessionUpdate) UnmarshalJSON(b []byte) error { @@ -2604,7 +3521,7 @@ func (u *SessionUpdate) UnmarshalJSON(b []byte) error { u.ToolCall = &v return nil case "tool_call_update": - var v SessionUpdateToolCallUpdate + var v SessionToolCallUpdate if json.Unmarshal(b, &v) != nil { return errors.New("invalid variant payload") } @@ -2618,14 +3535,14 @@ func (u *SessionUpdate) UnmarshalJSON(b []byte) error { u.Plan = &v return nil case "available_commands_update": - var v SessionUpdateAvailableCommandsUpdate + var v SessionAvailableCommandsUpdate if json.Unmarshal(b, &v) != nil { return errors.New("invalid variant payload") } u.AvailableCommandsUpdate = &v return nil case "current_mode_update": - var v SessionUpdateCurrentModeUpdate + var v SessionCurrentModeUpdate if json.Unmarshal(b, &v) != nil { return errors.New("invalid variant payload") } @@ -2705,7 +3622,7 @@ func (u *SessionUpdate) UnmarshalJSON(b []byte) error { } } { - var v SessionUpdateToolCallUpdate + var v SessionToolCallUpdate var match bool = true if _, ok := m["sessionUpdate"]; !ok { match = false @@ -2739,7 +3656,7 @@ func (u *SessionUpdate) UnmarshalJSON(b []byte) error { } } { - var v SessionUpdateAvailableCommandsUpdate + var v SessionAvailableCommandsUpdate var match bool = true if _, ok := m["sessionUpdate"]; !ok { match = false @@ -2756,7 +3673,7 @@ func (u *SessionUpdate) UnmarshalJSON(b []byte) error { } } { - var v SessionUpdateCurrentModeUpdate + var v SessionCurrentModeUpdate var match bool = true if _, ok := m["sessionUpdate"]; !ok { match = false @@ -2801,7 +3718,7 @@ func (u *SessionUpdate) UnmarshalJSON(b []byte) error { } } { - var v SessionUpdateToolCallUpdate + var v SessionToolCallUpdate if json.Unmarshal(b, &v) == nil { u.ToolCallUpdate = &v return nil @@ -2815,14 +3732,14 @@ func (u *SessionUpdate) UnmarshalJSON(b []byte) error { } } { - var v SessionUpdateAvailableCommandsUpdate + var v SessionAvailableCommandsUpdate if json.Unmarshal(b, &v) == nil { u.AvailableCommandsUpdate = &v return nil } } { - var v SessionUpdateCurrentModeUpdate + var v SessionCurrentModeUpdate if json.Unmarshal(b, &v) == nil { u.CurrentModeUpdate = &v return nil @@ -2978,14 +3895,18 @@ func (v *SetSessionModeRequest) Validate() error { // Response to 'session/set_mode' method. type SetSessionModeResponse struct { - Meta any `json:"meta,omitempty"` + Meta any `json:"_meta,omitempty"` } func (v *SetSessionModeResponse) Validate() error { return nil } -// **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. Request parameters for setting a session model. +// **UNSTABLE** +// +// This capability is not part of the spec yet, and may be removed or changed at any point. +// +// Request parameters for setting a session model. type SetSessionModelRequest struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` @@ -2999,7 +3920,11 @@ func (v *SetSessionModelRequest) Validate() error { return nil } -// **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. Response to 'session/set_model' method. +// **UNSTABLE** +// +// This capability is not part of the spec yet, and may be removed or changed at any point. +// +// Response to 'session/set_model' method. type SetSessionModelResponse struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` @@ -3009,7 +3934,9 @@ func (v *SetSessionModelResponse) Validate() error { return nil } -// Reasons why an agent stops processing a prompt turn. See protocol docs: [Stop Reasons](https://agentclientprotocol.com/protocol/prompt-turn#stop-reasons) +// Reasons why an agent stops processing a prompt turn. +// +// See protocol docs: [Stop Reasons](https://agentclientprotocol.com/protocol/prompt-turn#stop-reasons) type StopReason string const ( @@ -3066,14 +3993,6 @@ func (v *TerminalOutputResponse) Validate() error { return nil } -// Text provided to or from an LLM. -type TextContent struct { - // Extension point for implementations - Meta any `json:"_meta,omitempty"` - Annotations *Annotations `json:"annotations,omitempty"` - Text string `json:"text"` -} - // Text-based resource contents. type TextResourceContents struct { // Extension point for implementations @@ -3083,29 +4002,12 @@ type TextResourceContents struct { Uri string `json:"uri"` } -// Represents a tool call that the language model has requested. Tool calls are actions that the agent executes on behalf of the language model, such as reading files, executing code, or fetching data from external sources. See protocol docs: [Tool Calls](https://agentclientprotocol.com/protocol/tool-calls) -type ToolCall struct { - // Extension point for implementations - Meta any `json:"_meta,omitempty"` - // Content produced by the tool call. - Content []ToolCallContent `json:"content,omitempty"` - // The category of tool being invoked. Helps clients choose appropriate icons and UI treatment. - Kind ToolKind `json:"kind,omitempty"` - // File locations affected by this tool call. Enables "follow-along" features in clients. - Locations []ToolCallLocation `json:"locations,omitempty"` - // Raw input parameters sent to the tool. - RawInput any `json:"rawInput,omitempty"` - // Raw output returned by the tool. - RawOutput any `json:"rawOutput,omitempty"` - // Current execution status of the tool call. - Status ToolCallStatus `json:"status,omitempty"` - // Human-readable title describing what the tool is doing. - Title string `json:"title"` - // Unique identifier for this tool call within the session. - ToolCallId ToolCallId `json:"toolCallId"` -} - -// Content produced by a tool call. Tool calls can produce different types of content including standard content blocks (text, images) or file diffs. See protocol docs: [Content](https://agentclientprotocol.com/protocol/tool-calls#content) +// Content produced by a tool call. +// +// Tool calls can produce different types of content including +// standard content blocks (text, images) or file diffs. +// +// See protocol docs: [Content](https://agentclientprotocol.com/protocol/tool-calls#content) // Standard content block (text, images, resources). type ToolCallContentContent struct { // The actual content block. @@ -3126,7 +4028,11 @@ type ToolCallContentDiff struct { Type string `json:"type"` } -// Embed a terminal created with 'terminal/create' by its id. The terminal must be added before calling 'terminal/release'. See protocol docs: [Terminal](https://agentclientprotocol.com/protocol/terminal) +// Embed a terminal created with 'terminal/create' by its id. +// +// The terminal must be added before calling 'terminal/release'. +// +// See protocol docs: [Terminal](https://agentclientprotocol.com/protocol/terminal) type ToolCallContentTerminal struct { TerminalId string `json:"terminalId"` Type string `json:"type"` @@ -3137,7 +4043,11 @@ type ToolCallContent struct { Content *ToolCallContentContent `json:"-"` // File modification shown as a diff. Diff *ToolCallContentDiff `json:"-"` - // Embed a terminal created with 'terminal/create' by its id. The terminal must be added before calling 'terminal/release'. See protocol docs: [Terminal](https://agentclientprotocol.com/protocol/terminal) + // Embed a terminal created with 'terminal/create' by its id. + // + // The terminal must be added before calling 'terminal/release'. + // + // See protocol docs: [Terminal](https://agentclientprotocol.com/protocol/terminal) Terminal *ToolCallContentTerminal `json:"-"` } @@ -3312,7 +4222,12 @@ func (u *ToolCallContent) Validate() error { // Unique identifier for a tool call within a session. type ToolCallId string -// A file location being accessed or modified by a tool. Enables clients to implement "follow-along" features that track which files the agent is working with in real-time. See protocol docs: [Following the Agent](https://agentclientprotocol.com/protocol/tool-calls#following-the-agent) +// A file location being accessed or modified by a tool. +// +// Enables clients to implement "follow-along" features that track +// which files the agent is working with in real-time. +// +// See protocol docs: [Following the Agent](https://agentclientprotocol.com/protocol/tool-calls#following-the-agent) type ToolCallLocation struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` @@ -3322,7 +4237,11 @@ type ToolCallLocation struct { Path string `json:"path"` } -// Execution status of a tool call. Tool calls progress through different statuses during their lifecycle. See protocol docs: [Status](https://agentclientprotocol.com/protocol/tool-calls#status) +// Execution status of a tool call. +// +// Tool calls progress through different statuses during their lifecycle. +// +// See protocol docs: [Status](https://agentclientprotocol.com/protocol/tool-calls#status) type ToolCallStatus string const ( @@ -3332,36 +4251,12 @@ const ( ToolCallStatusFailed ToolCallStatus = "failed" ) -// An update to an existing tool call. Used to report progress and results as tools execute. All fields except the tool call ID are optional - only changed fields need to be included. See protocol docs: [Updating](https://agentclientprotocol.com/protocol/tool-calls#updating) -type ToolCallUpdate struct { - // Extension point for implementations - Meta any `json:"_meta,omitempty"` - // Replace the content collection. - Content []ToolCallContent `json:"content,omitempty"` - // Update the tool kind. - Kind *ToolKind `json:"kind,omitempty"` - // Replace the locations collection. - Locations []ToolCallLocation `json:"locations,omitempty"` - // Update the raw input. - RawInput any `json:"rawInput,omitempty"` - // Update the raw output. - RawOutput any `json:"rawOutput,omitempty"` - // Update the execution status. - Status *ToolCallStatus `json:"status,omitempty"` - // Update the human-readable title. - Title *string `json:"title,omitempty"` - // The ID of the tool call being updated. - ToolCallId ToolCallId `json:"toolCallId"` -} - -func (t *ToolCallUpdate) Validate() error { - if t.ToolCallId == "" { - return fmt.Errorf("toolCallId is required") - } - return nil -} - -// Categories of tools that can be invoked. Tool kinds help clients choose appropriate icons and optimize how they display tool execution progress. See protocol docs: [Creating](https://agentclientprotocol.com/protocol/tool-calls#creating) +// Categories of tools that can be invoked. +// +// Tool kinds help clients choose appropriate icons and optimize how they +// display tool execution progress. +// +// See protocol docs: [Creating](https://agentclientprotocol.com/protocol/tool-calls#creating) type ToolKind string const ( @@ -3408,7 +4303,9 @@ func (v *WaitForTerminalExitResponse) Validate() error { return nil } -// Request to write content to a text file. Only available if the client supports the 'fs.writeTextFile' capability. +// Request to write content to a text file. +// +// Only available if the client supports the 'fs.writeTextFile' capability. type WriteTextFileRequest struct { // Extension point for implementations Meta any `json:"_meta,omitempty"` @@ -3441,15 +4338,29 @@ func (v *WriteTextFileResponse) Validate() error { } type Agent interface { - // Request parameters for the authenticate method. Specifies which authentication method to use. + // Request parameters for the authenticate method. + // + // Specifies which authentication method to use. Authenticate(ctx context.Context, params AuthenticateRequest) (AuthenticateResponse, error) - // Request parameters for the initialize method. Sent by the client to establish connection and negotiate capabilities. See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization) + // Request parameters for the initialize method. + // + // Sent by the client to establish connection and negotiate capabilities. + // + // See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization) Initialize(ctx context.Context, params InitializeRequest) (InitializeResponse, error) - // Notification to cancel ongoing operations for a session. See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation) + // Notification to cancel ongoing operations for a session. + // + // See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation) Cancel(ctx context.Context, params CancelNotification) error - // Request parameters for creating a new session. See protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol/session-setup#creating-a-session) + // Request parameters for creating a new session. + // + // See protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol/session-setup#creating-a-session) NewSession(ctx context.Context, params NewSessionRequest) (NewSessionResponse, error) - // Request parameters for sending a user prompt to the agent. Contains the user's message and any additional context. See protocol docs: [User Message](https://agentclientprotocol.com/protocol/prompt-turn#1-user-message) + // Request parameters for sending a user prompt to the agent. + // + // Contains the user's message and any additional context. + // + // See protocol docs: [User Message](https://agentclientprotocol.com/protocol/prompt-turn#1-user-message) Prompt(ctx context.Context, params PromptRequest) (PromptResponse, error) // Request parameters for setting a session mode. SetSessionMode(ctx context.Context, params SetSessionModeRequest) (SetSessionModeResponse, error) @@ -3457,23 +4368,43 @@ type Agent interface { // AgentLoader defines optional support for loading sessions. Implement and advertise the capability to enable 'session/load'. type AgentLoader interface { - // Request parameters for loading an existing session. Only available if the Agent supports the 'loadSession' capability. See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions) + // Request parameters for loading an existing session. + // + // Only available if the Agent supports the 'loadSession' capability. + // + // See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions) LoadSession(ctx context.Context, params LoadSessionRequest) (LoadSessionResponse, error) } // AgentExperimental defines unstable methods that are not part of the official spec. These may change or be removed without notice. type AgentExperimental interface { - // **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. Request parameters for setting a session model. + // **UNSTABLE** + // + // This capability is not part of the spec yet, and may be removed or changed at any point. + // + // Request parameters for setting a session model. SetSessionModel(ctx context.Context, params SetSessionModelRequest) (SetSessionModelResponse, error) } type Client interface { - // Request to read content from a text file. Only available if the client supports the 'fs.readTextFile' capability. + // Request to read content from a text file. + // + // Only available if the client supports the 'fs.readTextFile' capability. ReadTextFile(ctx context.Context, params ReadTextFileRequest) (ReadTextFileResponse, error) - // Request to write content to a text file. Only available if the client supports the 'fs.writeTextFile' capability. + // Request to write content to a text file. + // + // Only available if the client supports the 'fs.writeTextFile' capability. WriteTextFile(ctx context.Context, params WriteTextFileRequest) (WriteTextFileResponse, error) - // Request for user permission to execute a tool call. Sent when the agent needs authorization before performing a sensitive operation. See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission) + // Request for user permission to execute a tool call. + // + // Sent when the agent needs authorization before performing a sensitive operation. + // + // See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission) RequestPermission(ctx context.Context, params RequestPermissionRequest) (RequestPermissionResponse, error) - // Notification containing a session update from the agent. Used to stream real-time progress and results during prompt processing. See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output) + // Notification containing a session update from the agent. + // + // Used to stream real-time progress and results during prompt processing. + // + // See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output) SessionUpdate(ctx context.Context, params SessionNotification) error // Request to create a new terminal and execute a command. CreateTerminal(ctx context.Context, params CreateTerminalRequest) (CreateTerminalResponse, error) diff --git a/version b/version index 76914dd..844f6a9 100644 --- a/version +++ b/version @@ -1 +1 @@ -0.4.9 +0.6.3