@@ -2,6 +2,8 @@ package cmd
22
33import (
44 "context"
5+ "encoding/json"
6+ "fmt"
57 "io"
68
79 glean "github.com/gleanwork/api-client-go"
@@ -11,10 +13,21 @@ import (
1113 "github.com/spf13/cobra"
1214)
1315
14- // agentIDRequest is a CLI-only request struct for commands that take an agent
15- // ID as their only input. Using camelCase JSON tag for CLI consistency.
16+ // agentIDRequest is a CLI-only request struct for commands whose only input
17+ // is an agent ID. The snake_case tag matches the platform input shape;
18+ // cmdutil transparently normalizes camelCase agentId.
1619type agentIDRequest struct {
17- AgentID string `json:"agentId"`
20+ AgentID string `json:"agent_id"`
21+ }
22+
23+ // agentRunRequest is the CLI request for `agents run`. The platform route
24+ // takes the agent ID as a path parameter (POST /api/agents/{agent_id}/runs),
25+ // so the CLI folds it into the --json body alongside the run inputs.
26+ type agentRunRequest struct {
27+ AgentID string `json:"agent_id"`
28+ Input map [string ]any `json:"input,omitempty"`
29+ Messages []components.PlatformMessage `json:"messages,omitempty"`
30+ Metadata map [string ]any `json:"metadata,omitempty"`
1831}
1932
2033func NewCmdAgents () * cobra.Command {
@@ -25,11 +38,19 @@ func NewCmdAgents() *cobra.Command {
2538
2639Agents are AI-powered workflows that can search, reason, and act on your company's knowledge.
2740
41+ Agent commands are served by the platform API (/api/agents/...) and responses
42+ use its snake_case shape. list/get/schemas fall back to the classic API with a
43+ warning when the platform API is not enabled; run does not fall back
44+ automatically because its request body differs between the two surfaces. Set
45+ GLEAN_LEGACY_APIS=1 to use the classic API directly (run then expects the
46+ classic messages/fragments body).
47+
2848Example:
2949 glean agents list
30- glean agents get --json '{"agentId":"<id>"}'
31- glean agents schemas --json '{"agentId":"<id>"}'
32- glean agents run --json '{"agentId":"<id>","messages":[{"author":"USER","fragments":[{"text":"summarize Q1 results"}]}]}'` ,
50+ glean agents get --json '{"agent_id":"<id>"}'
51+ glean agents schemas --json '{"agent_id":"<id>"}'
52+ glean agents run --json '{"agent_id":"<id>","input":{"query":"summarize Q1 results"}}'
53+ glean agents run --json '{"agent_id":"<id>","messages":[{"role":"user","content":[{"type":"text","text":"summarize Q1 results"}]}]}'` ,
3354 }
3455 cmd .AddCommand (
3556 newAgentsListCmd (),
@@ -40,26 +61,56 @@ Example:
4061 return cmd
4162}
4263
64+ // agentsListTextFn renders whichever agents list shape the request produced:
65+ // the platform response (default) or the classic response (legacy fallback).
66+ func agentsListTextFn (w io.Writer , v any ) error {
67+ header := []string {"ID" , "NAME" , "DESCRIPTION" }
68+ switch resp := v .(type ) {
69+ case * components.PlatformAgentsSearchResponse :
70+ rows := make ([][]string , len (resp .Agents ))
71+ for i , a := range resp .Agents {
72+ desc := ""
73+ if a .Description != nil {
74+ desc = output .Truncate (* a .Description , 60 )
75+ }
76+ rows [i ] = []string {a .AgentID , a .Name , desc }
77+ }
78+ return output .WriteTable (w , header , rows )
79+ case * components.SearchAgentsResponse :
80+ rows := make ([][]string , len (resp .Agents ))
81+ for i , a := range resp .Agents {
82+ desc := ""
83+ if a .Description != nil {
84+ desc = output .Truncate (* a .Description , 60 )
85+ }
86+ rows [i ] = []string {a .AgentID , a .Name , desc }
87+ }
88+ return output .WriteTable (w , header , rows )
89+ default :
90+ return output .WriteJSON (w , v )
91+ }
92+ }
93+
4394func newAgentsListCmd () * cobra.Command {
44- return cmdutil .Build (cmdutil.Spec [components.SearchAgentsRequest ]{
45- Use : "list" ,
46- Short : "List available agents" ,
47- TextFn : func (w io.Writer , v any ) error {
48- resp , ok := v .(* components.SearchAgentsResponse )
49- if ! ok {
50- return output .WriteJSON (w , v )
95+ return cmdutil .Build (cmdutil.Spec [components.PlatformAgentsSearchRequest ]{
96+ Use : "list" ,
97+ Short : "List available agents" ,
98+ Endpoint : "/api/agents/search" ,
99+ TextFn : agentsListTextFn ,
100+ Run : func (ctx context.Context , sdk * glean.Glean , req components.PlatformAgentsSearchRequest ) (any , error ) {
101+ resp , err := sdk .Agents .Search (ctx , req )
102+ if err != nil {
103+ return nil , err
51104 }
52- rows := make ([][]string , len (resp .Agents ))
53- for i , a := range resp .Agents {
54- desc := ""
55- if a .Description != nil {
56- desc = output .Truncate (* a .Description , 60 )
105+ return resp .PlatformAgentsSearchResponse , nil
106+ },
107+ LegacyRun : func (ctx context.Context , sdk * glean.Glean , rawJSON []byte ) (any , error ) {
108+ var req components.SearchAgentsRequest
109+ if len (rawJSON ) > 0 {
110+ if err := json .Unmarshal (rawJSON , & req ); err != nil {
111+ return nil , fmt .Errorf ("invalid --json: %w" , err )
57112 }
58- rows [i ] = []string {a .AgentID , a .Name , desc }
59113 }
60- return output .WriteTable (w , []string {"ID" , "NAME" , "DESCRIPTION" }, rows )
61- },
62- Run : func (ctx context.Context , sdk * glean.Glean , req components.SearchAgentsRequest ) (any , error ) {
63114 resp , err := sdk .Client .Agents .List (ctx , req )
64115 if err != nil {
65116 return nil , err
@@ -69,12 +120,34 @@ func newAgentsListCmd() *cobra.Command {
69120 })
70121}
71122
123+ // parseAgentIDRequest is the shared LegacyRun payload parse for get/schemas:
124+ // the input is a bare agent ID, identical on both surfaces.
125+ func parseAgentIDRequest (rawJSON []byte ) (agentIDRequest , error ) {
126+ var req agentIDRequest
127+ if err := json .Unmarshal (rawJSON , & req ); err != nil {
128+ return req , fmt .Errorf ("invalid --json: %w" , err )
129+ }
130+ return req , nil
131+ }
132+
72133func newAgentsGetCmd () * cobra.Command {
73134 return cmdutil .Build (cmdutil.Spec [agentIDRequest ]{
74135 Use : "get" ,
75136 Short : "Get an agent by ID" ,
76137 JSONRequired : true ,
138+ Endpoint : "/api/agents/{agent_id}" ,
77139 Run : func (ctx context.Context , sdk * glean.Glean , req agentIDRequest ) (any , error ) {
140+ resp , err := sdk .Agents .Get (ctx , req .AgentID )
141+ if err != nil {
142+ return nil , err
143+ }
144+ return resp .PlatformAgentGetResponse , nil
145+ },
146+ LegacyRun : func (ctx context.Context , sdk * glean.Glean , rawJSON []byte ) (any , error ) {
147+ req , err := parseAgentIDRequest (rawJSON )
148+ if err != nil {
149+ return nil , err
150+ }
78151 resp , err := sdk .Client .Agents .Retrieve (ctx , req .AgentID , nil , nil )
79152 if err != nil {
80153 return nil , err
@@ -89,7 +162,19 @@ func newAgentsSchemasCmd() *cobra.Command {
89162 Use : "schemas" ,
90163 Short : "Get the schemas for an agent" ,
91164 JSONRequired : true ,
165+ Endpoint : "/api/agents/{agent_id}/schemas" ,
92166 Run : func (ctx context.Context , sdk * glean.Glean , req agentIDRequest ) (any , error ) {
167+ resp , err := sdk .Agents .GetSchemas (ctx , req .AgentID , nil )
168+ if err != nil {
169+ return nil , err
170+ }
171+ return resp .PlatformAgentSchemasResponse , nil
172+ },
173+ LegacyRun : func (ctx context.Context , sdk * glean.Glean , rawJSON []byte ) (any , error ) {
174+ req , err := parseAgentIDRequest (rawJSON )
175+ if err != nil {
176+ return nil , err
177+ }
93178 resp , err := sdk .Client .Agents .RetrieveSchemas (ctx , req .AgentID , nil , nil )
94179 if err != nil {
95180 return nil , err
@@ -100,11 +185,34 @@ func newAgentsSchemasCmd() *cobra.Command {
100185}
101186
102187func newAgentsRunCmd () * cobra.Command {
103- return cmdutil .Build (cmdutil.Spec [components. AgentRunCreate ]{
188+ return cmdutil .Build (cmdutil.Spec [agentRunRequest ]{
104189 Use : "run" ,
105190 Short : "Run an agent (synchronous)" ,
106191 JSONRequired : true ,
107- Run : func (ctx context.Context , sdk * glean.Glean , req components.AgentRunCreate ) (any , error ) {
192+ Endpoint : "/api/agents/{agent_id}/runs" ,
193+ // The run body is user-authored and shaped differently on the two
194+ // surfaces (platform input/messages vs classic messages/fragments),
195+ // so gate-closed errors instead of silently replaying the payload.
196+ FallbackMode : cmdutil .FallbackEnvOnly ,
197+ Run : func (ctx context.Context , sdk * glean.Glean , req agentRunRequest ) (any , error ) {
198+ if req .AgentID == "" {
199+ return nil , fmt .Errorf ("agent_id is required in the --json payload" )
200+ }
201+ resp , err := sdk .Agents .CreateRun (ctx , req .AgentID , components.PlatformAgentRunCreateRequest {
202+ Input : req .Input ,
203+ Messages : req .Messages ,
204+ Metadata : req .Metadata ,
205+ })
206+ if err != nil {
207+ return nil , err
208+ }
209+ return resp .PlatformAgentRunWaitResponse , nil
210+ },
211+ LegacyRun : func (ctx context.Context , sdk * glean.Glean , rawJSON []byte ) (any , error ) {
212+ var req components.AgentRunCreate
213+ if err := json .Unmarshal (rawJSON , & req ); err != nil {
214+ return nil , fmt .Errorf ("invalid --json: %w" , err )
215+ }
108216 resp , err := sdk .Client .Agents .Run (ctx , req )
109217 if err != nil {
110218 return nil , err
0 commit comments