Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

chore(codersdk/toolsdk): improve static analyzability of toolsdk.Tools#17562

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
johnstcn merged 12 commits intomainfromcj/toolsdk-refactor
Apr 29, 2025

Conversation

johnstcn
Copy link
Member

@johnstcnjohnstcn commentedApr 24, 2025
edited
Loading

  • Refactors toolsdk.Tools to remove opaquemap[string]any argument in favour of typed args structs.
  • Refactors toolsdk.Tools to remove opaque passing of dependencies viacontext.Context in favour of a tool dependencies struct.
  • Adds panic recovery and clean context middleware to all tools.
  • AddsGenericTool implementation to allow keepingtoolsdk.All with uniform type signature while maintaining type information in handlers.
  • Adds stricter checks topatchWorkspaceAgentAppStatus handler.

@johnstcnjohnstcn self-assigned thisApr 24, 2025
@johnstcnjohnstcn changed the titlechore(codersdk/toolsdk): add typed argument to toolsdk.Toolchore(codersdk/toolsdk): improve static analyzability of toolsdk.ToolsApr 24, 2025
@johnstcnjohnstcn marked this pull request as ready for reviewApril 24, 2025 15:21
Comment on lines 348 to 371
if len(req.Message) > 160 {
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
Message: "Message is too long.",
Detail: "Message must be less than 160 characters.",
Validations: []codersdk.ValidationError{
{Field: "message", Detail: "Message must be less than 160 characters."},
},
})
return
}

switch req.State {
case codersdk.WorkspaceAppStatusStateComplete, codersdk.WorkspaceAppStatusStateFailure, codersdk.WorkspaceAppStatusStateWorking: // valid states
default:
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
Message: "Invalid state provided.",
Detail: fmt.Sprintf("invalid state: %q", req.State),
Validations: []codersdk.ValidationError{
{Field: "state", Detail: "State must be one of: complete, failure, working."},
},
})
return
}

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

review: moved this check to the handler instead.

Comment on lines 34 to 53
// Generic returns a type-erased version of a TypedTool where the arguments and
// return values are converted to/from json.RawMessage.
// This allows the tool to be referenced without knowing the concrete arguments
// or return values. The original TypedHandlerFunc is wrapped to handle type
// conversion.
func (t Tool[Arg, Ret]) Generic() GenericTool {
return GenericTool{
Tool: t.Tool,
Handler: func(ctx context.Context, args map[string]any) (any, error) {
return t.Handler(ctx, args)
},
Handler: wrap(func(ctx context.Context, tb Deps, args json.RawMessage) (json.RawMessage, error) {
var typedArgs Arg
if err := json.Unmarshal(args, &typedArgs); err != nil {
return nil, xerrors.Errorf("failed to unmarshal args: %w", err)
}
ret, err := t.Handler(ctx, tb, typedArgs)
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(ret); err != nil {
return json.RawMessage{}, err
}
return buf.Bytes(), err
}, WithCleanContext, WithRecover),
Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

review: this was the best way I could find to maintain type safety while allowing external callers to treat all the tools equivalently.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

The other option would be to attempt to fill out theArg via reflection, taking amap[string]any as "raw" input. Would definitely be more code, but might be a performance optimization in future for the MCP server which already parses the JSON of the tool invocation.

johnstcn reacted with thumbs up emoji
var (
// All is a list of all tools that can be used in the Coder CLI.
// When you add a new tool, be sure to include it here!
All = []Tool[any]{
CreateTemplateVersion.Generic(),
All = []GenericTool{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

It would be useful to have different lists depending on whether you have an agent client and slug.

Comment on lines 34 to 53
// Generic returns a type-erased version of a TypedTool where the arguments and
// return values are converted to/from json.RawMessage.
// This allows the tool to be referenced without knowing the concrete arguments
// or return values. The original TypedHandlerFunc is wrapped to handle type
// conversion.
func (t Tool[Arg, Ret]) Generic() GenericTool {
return GenericTool{
Tool: t.Tool,
Handler: func(ctx context.Context, args map[string]any) (any, error) {
return t.Handler(ctx, args)
},
Handler: wrap(func(ctx context.Context, tb Deps, args json.RawMessage) (json.RawMessage, error) {
var typedArgs Arg
if err := json.Unmarshal(args, &typedArgs); err != nil {
return nil, xerrors.Errorf("failed to unmarshal args: %w", err)
}
ret, err := t.Handler(ctx, tb, typedArgs)
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(ret); err != nil {
return json.RawMessage{}, err
}
return buf.Bytes(), err
}, WithCleanContext, WithRecover),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

The other option would be to attempt to fill out theArg via reflection, taking amap[string]any as "raw" input. Would definitely be more code, but might be a performance optimization in future for the MCP server which already parses the JSON of the tool invocation.

johnstcn reacted with thumbs up emoji
Copy link
Member

@kylecarbskylecarbs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I'm personally still in favor of the context...

We can still use*Deps as part of the context so notanything can be extracted, but all we're really doing is that, but with a layer of abstraction over all tools.

I don't want to cause Cian more rework so we can merge, but I don't think this accomplishes increased clarity or safety over doing the same thing, but in a context.

I really love how Cian did the args though - that is certainlymuch improved.

johnstcn reacted with heart emoji
@johnstcnjohnstcn merged commit2acf0ad intomainApr 29, 2025
29 checks passed
@johnstcnjohnstcn deleted the cj/toolsdk-refactor branchApril 29, 2025 15:05
@github-actionsgithub-actionsbot locked and limited conversation to collaboratorsApr 29, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account?Sign in.
Reviewers

@spikecurtisspikecurtisspikecurtis approved these changes

@kylecarbskylecarbskylecarbs approved these changes

Assignees

@johnstcnjohnstcn

Labels
None yet
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

3 participants
@johnstcn@spikecurtis@kylecarbs

[8]ページ先頭

©2009-2025 Movatter.jp