-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathenvelope.go
More file actions
136 lines (123 loc) · 3.25 KB
/
Copy pathenvelope.go
File metadata and controls
136 lines (123 loc) · 3.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package toolsy
import (
"mime"
"strings"
)
// ToolEnvelopeKind classifies a delivered tool payload without inspecting JSON shape.
type ToolEnvelopeKind string
const (
ToolEnvelopeKindResult ToolEnvelopeKind = "result"
ToolEnvelopeKindError ToolEnvelopeKind = "error"
)
// ToolDeliveryClass tells downstream renderers how technical the payload is.
type ToolDeliveryClass string
const (
DeliveryClassStructured ToolDeliveryClass = "structured"
DeliveryClassText ToolDeliveryClass = "text"
DeliveryClassBinary ToolDeliveryClass = "binary"
)
// ToolAudience describes the intended consumer of a tool payload.
type ToolAudience string
const (
AudienceModel ToolAudience = "model"
AudienceUser ToolAudience = "user"
AudienceInternal ToolAudience = "internal"
)
// ToolEnvelope is the typed result/error delivery contract for downstream inspection.
type ToolEnvelope struct {
Kind ToolEnvelopeKind
Error *ToolError
DeliveryClass ToolDeliveryClass
Audience ToolAudience
Raw []byte
MimeType string
Result any
Metadata map[string]any
}
// NewResultEnvelope builds a typed success envelope.
func NewResultEnvelope(
result any,
raw []byte,
mimeType string,
deliveryClass ToolDeliveryClass,
audience ToolAudience,
metadata map[string]any,
) *ToolEnvelope {
if deliveryClass == "" {
if textLikeMimeType(mimeType) {
deliveryClass = DeliveryClassText
} else {
deliveryClass = DeliveryClassStructured
}
}
if audience == "" {
audience = AudienceModel
}
return &ToolEnvelope{
Kind: ToolEnvelopeKindResult,
Error: nil,
DeliveryClass: deliveryClass,
Audience: audience,
Raw: append([]byte(nil), raw...),
MimeType: mimeType,
Result: result,
Metadata: deepCloneMap(metadata),
}
}
func textLikeMimeType(mimeType string) bool {
mediaType, _, err := mime.ParseMediaType(mimeType)
if err != nil {
mediaType = mimeType
}
mediaType = strings.ToLower(strings.TrimSpace(mediaType))
return strings.HasPrefix(mediaType, "text/") || mediaType == "application/x-ndjson"
}
// NewErrorEnvelope builds a typed error envelope.
func NewErrorEnvelope(
err *ToolError,
raw []byte,
mimeType string,
deliveryClass ToolDeliveryClass,
audience ToolAudience,
metadata map[string]any,
) *ToolEnvelope {
if deliveryClass == "" {
deliveryClass = DeliveryClassStructured
}
if audience == "" {
audience = AudienceModel
}
return &ToolEnvelope{
Kind: ToolEnvelopeKindError,
Error: err,
DeliveryClass: deliveryClass,
Audience: audience,
Raw: append([]byte(nil), raw...),
MimeType: mimeType,
Result: nil,
Metadata: deepCloneMap(metadata),
}
}
func cloneToolEnvelope(in *ToolEnvelope) *ToolEnvelope {
if in == nil {
return nil
}
return &ToolEnvelope{
Kind: in.Kind,
Error: cloneToolError(in.Error),
DeliveryClass: in.DeliveryClass,
Audience: in.Audience,
Raw: append([]byte(nil), in.Raw...),
MimeType: in.MimeType,
Result: in.Result,
Metadata: deepCloneMap(in.Metadata),
}
}
func cloneToolError(in *ToolError) *ToolError {
if in == nil {
return nil
}
out := *in
out.FixableArgs = append([]string(nil), in.FixableArgs...)
return &out
}