Skip to content

Commit 3bdf7c1

Browse files
committed
refactor: extract helpers to static file and optimize code generation
Change-Id: I410e8a8452949641864ca4e2e876ff2df6d71eee Signed-off-by: Thomas Kosiewski <tk@coder.com>
1 parent bdd623d commit 3bdf7c1

File tree

6 files changed

+267
-680
lines changed

6 files changed

+267
-680
lines changed

go/cmd/generate/internal/emit/helpers.go

Lines changed: 6 additions & 247 deletions
Original file line numberDiff line numberDiff line change
@@ -18,204 +18,6 @@ func WriteHelpersJen(outDir string, schema *load.Schema, _ *load.Meta) error {
1818
f := NewFile("acp")
1919
f.HeaderComment("Code generated by acp-go-generator; DO NOT EDIT.")
2020

21-
// Content helpers
22-
f.Comment("TextBlock constructs a text content block.")
23-
f.Func().Id("TextBlock").Params(Id("text").String()).Id("ContentBlock").Block(
24-
Return(Id("ContentBlock").Values(Dict{
25-
Id("Text"): Op("&").Id("ContentBlockText").Values(Dict{Id("Type"): Lit("text"), Id("Text"): Id("text")}),
26-
})),
27-
)
28-
f.Line()
29-
30-
f.Comment("ImageBlock constructs an inline image content block with base64-encoded data.")
31-
f.Func().Id("ImageBlock").Params(Id("data").String(), Id("mimeType").String()).Id("ContentBlock").Block(
32-
Return(Id("ContentBlock").Values(Dict{
33-
Id("Image"): Op("&").Id("ContentBlockImage").Values(Dict{Id("Type"): Lit("image"), Id("Data"): Id("data"), Id("MimeType"): Id("mimeType")}),
34-
})),
35-
)
36-
f.Line()
37-
38-
f.Comment("AudioBlock constructs an inline audio content block with base64-encoded data.")
39-
f.Func().Id("AudioBlock").Params(Id("data").String(), Id("mimeType").String()).Id("ContentBlock").Block(
40-
Return(Id("ContentBlock").Values(Dict{
41-
Id("Audio"): Op("&").Id("ContentBlockAudio").Values(Dict{Id("Type"): Lit("audio"), Id("Data"): Id("data"), Id("MimeType"): Id("mimeType")}),
42-
})),
43-
)
44-
f.Line()
45-
46-
f.Comment("ResourceLinkBlock constructs a resource_link content block with a name and URI.")
47-
f.Func().Id("ResourceLinkBlock").Params(Id("name").String(), Id("uri").String()).Id("ContentBlock").Block(
48-
Return(Id("ContentBlock").Values(Dict{
49-
Id("ResourceLink"): Op("&").Id("ContentBlockResourceLink").Values(Dict{Id("Type"): Lit("resource_link"), Id("Name"): Id("name"), Id("Uri"): Id("uri")}),
50-
})),
51-
)
52-
f.Line()
53-
54-
f.Comment("ResourceBlock wraps an embedded resource as a content block.")
55-
f.Func().Id("ResourceBlock").Params(Id("res").Id("EmbeddedResource")).Id("ContentBlock").Block(
56-
Var().Id("r").Id("EmbeddedResource").Op("=").Id("res"),
57-
Return(Id("ContentBlock").Values(Dict{
58-
Id("Resource"): Op("&").Id("ContentBlockResource").Values(Dict{Id("Type"): Lit("resource"), Id("Resource"): Id("r").Dot("Resource")}),
59-
})),
60-
)
61-
f.Line()
62-
63-
// ToolCall content helpers
64-
f.Comment("ToolContent wraps a content block as tool-call content.")
65-
f.Func().Id("ToolContent").Params(Id("block").Id("ContentBlock")).Id("ToolCallContent").Block(
66-
Return(Id("ToolCallContent").Values(Dict{
67-
Id("Content"): Op("&").Id("ToolCallContentContent").Values(Dict{Id("Content"): Id("block"), Id("Type"): Lit("content")}),
68-
})),
69-
)
70-
f.Line()
71-
72-
f.Comment("ToolDiffContent constructs a diff tool-call content. If oldText is omitted, the field is left empty.")
73-
f.Func().Id("ToolDiffContent").Params(Id("path").String(), Id("newText").String(), Id("oldText").Op("...").String()).Id("ToolCallContent").Block(
74-
Var().Id("o").Op("*").String(),
75-
If(Id("len").Call(Id("oldText")).Op(">").Lit(0)).Block(
76-
Id("o").Op("=").Op("&").Id("oldText").Index(Lit(0)),
77-
),
78-
Return(Id("ToolCallContent").Values(Dict{
79-
Id("Diff"): Op("&").Id("ToolCallContentDiff").Values(Dict{Id("Path"): Id("path"), Id("NewText"): Id("newText"), Id("OldText"): Id("o"), Id("Type"): Lit("diff")}),
80-
})),
81-
)
82-
f.Line()
83-
84-
f.Comment("ToolTerminalRef constructs a terminal reference tool-call content.")
85-
f.Func().Id("ToolTerminalRef").Params(Id("terminalId").String()).Id("ToolCallContent").Block(
86-
Return(Id("ToolCallContent").Values(Dict{
87-
Id("Terminal"): Op("&").Id("ToolCallContentTerminal").Values(Dict{Id("TerminalId"): Id("terminalId"), Id("Type"): Lit("terminal")}),
88-
})),
89-
)
90-
f.Line()
91-
92-
// Generic pointer helper
93-
f.Comment("Ptr returns a pointer to v.")
94-
f.Func().Id("Ptr").Types(Id("T").Any()).Params(Id("v").Id("T")).Op("*").Id("T").Block(
95-
Return(Op("&").Id("v")),
96-
)
97-
98-
// SessionUpdate helpers (friendly aliases)
99-
f.Line()
100-
f.Comment("UpdateUserMessage constructs a user_message_chunk update with the given content.")
101-
f.Func().Id("UpdateUserMessage").Params(Id("content").Id("ContentBlock")).Id("SessionUpdate").Block(
102-
Return(Id("SessionUpdate").Values(Dict{Id("UserMessageChunk"): Op("&").Id("SessionUpdateUserMessageChunk").Values(Dict{Id("Content"): Id("content")})})),
103-
)
104-
f.Comment("UpdateUserMessageText constructs a user_message_chunk update from text.")
105-
f.Func().Id("UpdateUserMessageText").Params(Id("text").String()).Id("SessionUpdate").Block(
106-
Return(Id("UpdateUserMessage").Call(Id("TextBlock").Call(Id("text")))),
107-
)
108-
109-
f.Comment("UpdateAgentMessage constructs an agent_message_chunk update with the given content.")
110-
f.Func().Id("UpdateAgentMessage").Params(Id("content").Id("ContentBlock")).Id("SessionUpdate").Block(
111-
Return(Id("SessionUpdate").Values(Dict{Id("AgentMessageChunk"): Op("&").Id("SessionUpdateAgentMessageChunk").Values(Dict{Id("Content"): Id("content")})})),
112-
)
113-
f.Comment("UpdateAgentMessageText constructs an agent_message_chunk update from text.")
114-
f.Func().Id("UpdateAgentMessageText").Params(Id("text").String()).Id("SessionUpdate").Block(
115-
Return(Id("UpdateAgentMessage").Call(Id("TextBlock").Call(Id("text")))),
116-
)
117-
118-
f.Comment("UpdateAgentThought constructs an agent_thought_chunk update with the given content.")
119-
f.Func().Id("UpdateAgentThought").Params(Id("content").Id("ContentBlock")).Id("SessionUpdate").Block(
120-
Return(Id("SessionUpdate").Values(Dict{Id("AgentThoughtChunk"): Op("&").Id("SessionUpdateAgentThoughtChunk").Values(Dict{Id("Content"): Id("content")})})),
121-
)
122-
f.Comment("UpdateAgentThoughtText constructs an agent_thought_chunk update from text.")
123-
f.Func().Id("UpdateAgentThoughtText").Params(Id("text").String()).Id("SessionUpdate").Block(
124-
Return(Id("UpdateAgentThought").Call(Id("TextBlock").Call(Id("text")))),
125-
)
126-
127-
f.Comment("UpdatePlan constructs a plan update with the provided entries.")
128-
f.Func().Id("UpdatePlan").Params(Id("entries").Op("...").Id("PlanEntry")).Id("SessionUpdate").Block(
129-
Return(Id("SessionUpdate").Values(Dict{Id("Plan"): Op("&").Id("SessionUpdatePlan").Values(Dict{Id("Entries"): Id("entries")})})),
130-
)
131-
132-
// Tool call start helpers with functional options (friendly aliases)
133-
f.Line()
134-
f.Type().Id("ToolCallStartOpt").Func().Params(Id("tc").Op("*").Id("SessionUpdateToolCall"))
135-
f.Comment("StartToolCall constructs a tool_call update with required fields and applies optional modifiers.")
136-
f.Func().Id("StartToolCall").Params(Id("id").Id("ToolCallId"), Id("title").String(), Id("opts").Op("...").Id("ToolCallStartOpt")).Id("SessionUpdate").Block(
137-
Id("tc").Op(":=").Id("SessionUpdateToolCall").Values(Dict{Id("ToolCallId"): Id("id"), Id("Title"): Id("title")}),
138-
For(List(Id("_"), Id("opt")).Op(":=").Range().Id("opts")).Block(Id("opt").Call(Op("&").Id("tc"))),
139-
Return(Id("SessionUpdate").Values(Dict{Id("ToolCall"): Op("&").Id("tc")})),
140-
)
141-
f.Comment("WithStartKind sets the kind for a tool_call start update.")
142-
f.Func().Id("WithStartKind").Params(Id("k").Id("ToolKind")).Id("ToolCallStartOpt").Block(
143-
Return(Func().Params(Id("tc").Op("*").Id("SessionUpdateToolCall")).Block(Id("tc").Dot("Kind").Op("=").Id("k"))),
144-
)
145-
f.Comment("WithStartStatus sets the status for a tool_call start update.")
146-
f.Func().Id("WithStartStatus").Params(Id("s").Id("ToolCallStatus")).Id("ToolCallStartOpt").Block(
147-
Return(Func().Params(Id("tc").Op("*").Id("SessionUpdateToolCall")).Block(Id("tc").Dot("Status").Op("=").Id("s"))),
148-
)
149-
f.Comment("WithStartContent sets the initial content for a tool_call start update.")
150-
f.Func().Id("WithStartContent").Params(Id("c").Index().Id("ToolCallContent")).Id("ToolCallStartOpt").Block(
151-
Return(Func().Params(Id("tc").Op("*").Id("SessionUpdateToolCall")).Block(Id("tc").Dot("Content").Op("=").Id("c"))),
152-
)
153-
f.Comment("WithStartLocations sets file locations and, if a single path is provided and rawInput is empty, mirrors it as rawInput.path.")
154-
f.Func().Id("WithStartLocations").Params(Id("l").Index().Id("ToolCallLocation")).Id("ToolCallStartOpt").Block(
155-
Return(Func().Params(Id("tc").Op("*").Id("SessionUpdateToolCall")).BlockFunc(func(g *Group) {
156-
g.Id("tc").Dot("Locations").Op("=").Id("l")
157-
g.If(Id("len").Call(Id("l")).Op("==").Lit(1).Op("&&").Id("l").Index(Lit(0)).Dot("Path").Op("!=").Lit("")).BlockFunc(func(h *Group) {
158-
// initialize rawInput if nil
159-
h.If(Id("tc").Dot("RawInput").Op("==").Nil()).Block(
160-
Id("tc").Dot("RawInput").Op("=").Map(String()).Any().Values(Dict{Lit("path"): Id("l").Index(Lit(0)).Dot("Path")}),
161-
).Else().BlockFunc(func(b *Group) {
162-
b.List(Id("m"), Id("ok")).Op(":=").Id("tc").Dot("RawInput").Assert(Map(String()).Any())
163-
b.If(Id("ok")).Block(
164-
If(List(Id("_"), Id("exists")).Op(":=").Id("m").Index(Lit("path")), Op("!").Id("exists")).Block(
165-
Id("m").Index(Lit("path")).Op("=").Id("l").Index(Lit(0)).Dot("Path"),
166-
),
167-
)
168-
})
169-
})
170-
})),
171-
)
172-
f.Comment("WithStartRawInput sets rawInput for a tool_call start update.")
173-
f.Func().Id("WithStartRawInput").Params(Id("v").Any()).Id("ToolCallStartOpt").Block(
174-
Return(Func().Params(Id("tc").Op("*").Id("SessionUpdateToolCall")).Block(Id("tc").Dot("RawInput").Op("=").Id("v"))),
175-
)
176-
f.Comment("WithStartRawOutput sets rawOutput for a tool_call start update.")
177-
f.Func().Id("WithStartRawOutput").Params(Id("v").Any()).Id("ToolCallStartOpt").Block(
178-
Return(Func().Params(Id("tc").Op("*").Id("SessionUpdateToolCall")).Block(Id("tc").Dot("RawOutput").Op("=").Id("v"))),
179-
)
180-
181-
// Tool call update helpers with functional options (pointer fields; friendly aliases)
182-
f.Line()
183-
f.Type().Id("ToolCallUpdateOpt").Func().Params(Id("tu").Op("*").Id("SessionUpdateToolCallUpdate"))
184-
f.Comment("UpdateToolCall constructs a tool_call_update with the given ID and applies optional modifiers.")
185-
f.Func().Id("UpdateToolCall").Params(Id("id").Id("ToolCallId"), Id("opts").Op("...").Id("ToolCallUpdateOpt")).Id("SessionUpdate").Block(
186-
Id("tu").Op(":=").Id("SessionUpdateToolCallUpdate").Values(Dict{Id("ToolCallId"): Id("id")}),
187-
For(List(Id("_"), Id("opt")).Op(":=").Range().Id("opts")).Block(Id("opt").Call(Op("&").Id("tu"))),
188-
Return(Id("SessionUpdate").Values(Dict{Id("ToolCallUpdate"): Op("&").Id("tu")})),
189-
)
190-
f.Comment("WithUpdateTitle sets the title for a tool_call_update.")
191-
f.Func().Id("WithUpdateTitle").Params(Id("t").String()).Id("ToolCallUpdateOpt").Block(
192-
Return(Func().Params(Id("tu").Op("*").Id("SessionUpdateToolCallUpdate")).Block(Id("tu").Dot("Title").Op("=").Id("Ptr").Call(Id("t")))),
193-
)
194-
f.Comment("WithUpdateKind sets the kind for a tool_call_update.")
195-
f.Func().Id("WithUpdateKind").Params(Id("k").Id("ToolKind")).Id("ToolCallUpdateOpt").Block(
196-
Return(Func().Params(Id("tu").Op("*").Id("SessionUpdateToolCallUpdate")).Block(Id("tu").Dot("Kind").Op("=").Id("Ptr").Call(Id("k")))),
197-
)
198-
f.Comment("WithUpdateStatus sets the status for a tool_call_update.")
199-
f.Func().Id("WithUpdateStatus").Params(Id("s").Id("ToolCallStatus")).Id("ToolCallUpdateOpt").Block(
200-
Return(Func().Params(Id("tu").Op("*").Id("SessionUpdateToolCallUpdate")).Block(Id("tu").Dot("Status").Op("=").Id("Ptr").Call(Id("s")))),
201-
)
202-
f.Comment("WithUpdateContent replaces the content collection for a tool_call_update.")
203-
f.Func().Id("WithUpdateContent").Params(Id("c").Index().Id("ToolCallContent")).Id("ToolCallUpdateOpt").Block(
204-
Return(Func().Params(Id("tu").Op("*").Id("SessionUpdateToolCallUpdate")).Block(Id("tu").Dot("Content").Op("=").Id("c"))),
205-
)
206-
f.Comment("WithUpdateLocations replaces the locations collection for a tool_call_update.")
207-
f.Func().Id("WithUpdateLocations").Params(Id("l").Index().Id("ToolCallLocation")).Id("ToolCallUpdateOpt").Block(
208-
Return(Func().Params(Id("tu").Op("*").Id("SessionUpdateToolCallUpdate")).Block(Id("tu").Dot("Locations").Op("=").Id("l"))),
209-
)
210-
f.Comment("WithUpdateRawInput sets rawInput for a tool_call_update.")
211-
f.Func().Id("WithUpdateRawInput").Params(Id("v").Any()).Id("ToolCallUpdateOpt").Block(
212-
Return(Func().Params(Id("tu").Op("*").Id("SessionUpdateToolCallUpdate")).Block(Id("tu").Dot("RawInput").Op("=").Id("v"))),
213-
)
214-
f.Comment("WithUpdateRawOutput sets rawOutput for a tool_call_update.")
215-
f.Func().Id("WithUpdateRawOutput").Params(Id("v").Any()).Id("ToolCallUpdateOpt").Block(
216-
Return(Func().Params(Id("tu").Op("*").Id("SessionUpdateToolCallUpdate")).Block(Id("tu").Dot("RawOutput").Op("=").Id("v"))),
217-
)
218-
21921
// Schema-driven generic helpers: New<Union><Variant>(required fields only)
22022
// Iterate definitions deterministically
22123
keys := make([]string, 0, len(schema.Defs))
@@ -232,6 +34,12 @@ func WriteHelpersJen(outDir string, schema *load.Schema, _ *load.Meta) error {
23234
if isStringConstUnion(def) {
23335
continue
23436
}
37+
// Skip generating New... helpers for unions that have stable, static helpers
38+
// implemented in go/helpers.go.
39+
switch name {
40+
case "ContentBlock", "ToolCallContent", "SessionUpdate":
41+
continue
42+
}
23543
// Build variant info similarly to types emitter
23644
type vinfo struct {
23745
fieldName string
@@ -329,58 +137,9 @@ func WriteHelpersJen(outDir string, schema *load.Schema, _ *load.Meta) error {
329137
}
330138
}
331139

332-
// Friendly aliases: opinionated tool call starters for common cases
333-
// StartReadToolCall: sets kind=read, status=pending, locations=[{path}], rawInput={path}
334-
f.Comment("StartReadToolCall constructs a 'tool_call' update for reading a file: kind=read, status=pending, locations=[{path}], rawInput={path}.")
335-
f.Func().Id("StartReadToolCall").Params(
336-
Id("id").Id("ToolCallId"),
337-
Id("title").String(),
338-
Id("path").String(),
339-
Id("opts").Op("...").Id("ToolCallStartOpt"),
340-
).Id("SessionUpdate").Block(
341-
Id("base").Op(":=").Index().Id("ToolCallStartOpt").Values(
342-
Id("WithStartKind").Call(Id("ToolKindRead")),
343-
Id("WithStartStatus").Call(Id("ToolCallStatusPending")),
344-
Id("WithStartLocations").Call(
345-
Index().Id("ToolCallLocation").Values(
346-
Id("ToolCallLocation").Values(Dict{Id("Path"): Id("path")}),
347-
),
348-
),
349-
Id("WithStartRawInput").Call(Map(String()).Any().Values(Dict{Lit("path"): Id("path")})),
350-
),
351-
Id("args").Op(":=").Id("append").Call(Id("base"), Id("opts").Op("...")),
352-
Return(Id("StartToolCall").Call(Id("id"), Id("title"), Id("args").Op("..."))),
353-
)
354-
f.Line()
355-
// StartEditToolCall: sets kind=edit, status=pending, locations=[{path}], rawInput={path, content}
356-
f.Comment("StartEditToolCall constructs a 'tool_call' update for editing content: kind=edit, status=pending, locations=[{path}], rawInput={path, content}.")
357-
f.Func().Id("StartEditToolCall").Params(
358-
Id("id").Id("ToolCallId"),
359-
Id("title").String(),
360-
Id("path").String(),
361-
Id("content").Any(),
362-
Id("opts").Op("...").Id("ToolCallStartOpt"),
363-
).Id("SessionUpdate").Block(
364-
Id("base").Op(":=").Index().Id("ToolCallStartOpt").Values(
365-
Id("WithStartKind").Call(Id("ToolKindEdit")),
366-
Id("WithStartStatus").Call(Id("ToolCallStatusPending")),
367-
Id("WithStartLocations").Call(
368-
Index().Id("ToolCallLocation").Values(
369-
Id("ToolCallLocation").Values(Dict{Id("Path"): Id("path")}),
370-
),
371-
),
372-
Id("WithStartRawInput").Call(Map(String()).Any().Values(Dict{Lit("path"): Id("path"), Lit("content"): Id("content")})),
373-
),
374-
Id("args").Op(":=").Id("append").Call(Id("base"), Id("opts").Op("...")),
375-
Return(Id("StartToolCall").Call(Id("id"), Id("title"), Id("args").Op("..."))),
376-
)
377-
f.Line()
378-
379140
var buf bytes.Buffer
380141
if err := f.Render(&buf); err != nil {
381142
return err
382143
}
383144
return os.WriteFile(filepath.Join(outDir, "helpers_gen.go"), buf.Bytes(), 0o644)
384145
}
385-
386-
// Note: isStringConstUnion exists in types emitter; we reference that file-level function

0 commit comments

Comments
 (0)