aws / aws-sdk-go-v2

AWS SDK for the Go programming language.
https://aws.github.io/aws-sdk-go-v2/docs/
Apache License 2.0
2.68k stars 651 forks source link

Document examples for UnmarshalSmithyDocument don't work #2751

Open mgomes opened 3 months ago

mgomes commented 3 months ago

Describe the issue

Here is a minimally reproducible example of the issue I am running into:

package main

import (
    "fmt"
    "log"

    "github.com/aws/aws-sdk-go-v2/service/bedrockruntime/document"
)

func main() {
    doc := document.NewLazyDocument(map[string]interface{}{
        "param1": "value1",
    })

    var result map[string]interface{}
    err := doc.UnmarshalSmithyDocument(&result)
    if err != nil {
        log.Fatalf("Error unmarshalling Smithy document: %v", err)
    }

    fmt.Printf("Unmarshalled result: %+v\n", result)
}

Running this code produces the error: Error unmarshalling Smithy document: unsupported json type, *map[string]interface {}

Is NewLazyDocument storing the map as a pointer internally somehow and so it isn't getting recognized? It seems like it should work when looking at the decoder: https://github.com/aws/smithy-go/blob/main/document/json/decoder.go#L71.

Links

https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/omics/document

AWS Go SDK V2 Module Versions Used

1.23.4

RanVaknin commented 3 months ago

Hi @mgomes ,

Can you give us a little more info about how you are trying to use this document unmarshalling?

Thanks, Ran~

mgomes commented 3 months ago

Hi @RanVaknin :wave:,

I am using it with tool use via the converse API. When a tool is selected by the model a ToolUseBlock is returned. The Input field contains the arguments that need to be passed to the respective tool. I am having a hard time getting those values out as is.

It seems to work in code, but in my unit test it fails.

My code looks something like this:

var args map[string]interface{}
err := bedrockToolUse.Value.Input.UnmarshalSmithyDocument(&args)
if err != nil {
    slog.Error("unmarshalling tool arguments.", slog.Any("error", err))
    return toolCalls
}

The test attempts to construct some sample arguments:

name: "Valid tool use transformation",
input: &types.ContentBlockMemberToolUse{
    Value: types.ToolUseBlock{
        ToolUseId: aws.String("tool-id"),
        Name:      aws.String("test-tool"),
        Input: document.NewLazyDocument(map[string]interface{}{
            "param1": "value1",
        }),
    },
}

But it fails with the same error as the reproduction code I pasted. Any recommendations for a workaround?

RanVaknin commented 3 months ago

Hi there,

Thanks for the clarification. Admittedly I was not too familiar with the document deserializer because there are very few services that use it. Looking at the deserializer source code that gets generated for each client, there are two UnmarshalSmithyDocument methods. You can mock this one:

https://github.com/aws/aws-sdk-go-v2/blob/d1d210dd11afc2ef0efa2e980d6b6c09cac0f5cb/service/bedrockruntime/internal/document/document.go#L60-L63

Because that is the one that the actual API client uses. So in your case:

package main

import (
    "fmt"
    smithydocumentjson "github.com/aws/smithy-go/document/json"
    "log"
)

type mockDoc struct {
    mockedValue interface{}
}

func (m *mockDoc) UnmarshalSmithyDocument(v interface{}) error {
    decoder := smithydocumentjson.NewDecoder()
    return decoder.DecodeJSONInterface(m.mockedValue, v)
}

func main() {

    doc := mockDoc{
        map[string]interface{}{
            "param1": "value1",
        },
    }

    var result map[string]interface{}
    err := doc.UnmarshalSmithyDocument(&result)
    if err != nil {
        log.Fatalf("Error unmarshalling Smithy document: %v", err)
    }

    fmt.Printf("Unmarshalled result: %+v\n", result)
}

// Unmarshalled result: map[param1:value1]

Thanks, Ran~