Verified Commit 530031c2 authored by Michael Angelo Rivera's avatar Michael Angelo Rivera Committed by GitLab
Browse files

feat(orbit): add GetDsl for /api/v4/orbit/schema/dsl

Changelog: Improvements
parent 141aecc6
Loading
Loading
Loading
Loading
+65 −5
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package gitlab

import (
	"bytes"
	"encoding/json"
	"io"
	"net/http"
@@ -61,6 +62,23 @@ type (
		// https://docs.gitlab.com/api/orbit/#get-tools
		GetTools(options ...RequestOptionFunc) (*OrbitTools, *Response, error)

		// GetDsl returns the Orbit query DSL as a raw string body
		// from `GET /api/v4/orbit/schema/dsl`.
		//
		// The body is intended for agent consumption: format=raw
		// returns a JSON Schema document, format=llm returns a
		// JSON-encoded TOON grammar string. Both shapes are forwarded
		// verbatim — the Orbit team treats the DSL surface as
		// in-flux during beta and intentionally does not pin a typed
		// schema here.
		//
		// Note: This API is experimental and may change or be
		// removed in future versions.
		//
		// GitLab API docs:
		// https://docs.gitlab.com/api/orbit/#get-dsl
		GetDsl(opt *GetOrbitDslOptions, options ...RequestOptionFunc) (string, *Response, error)

		// Query executes an Orbit (Knowledge Graph) query.
		//
		// Note: This API is experimental and may change or be
@@ -266,6 +284,16 @@ type OrbitTool struct {
	Parameters  json.RawMessage `json:"parameters,omitempty"`
}

// GetOrbitDslOptions represents the available GetDsl() options.
//
// GitLab API docs: https://docs.gitlab.com/api/orbit/#get-dsl
type GetOrbitDslOptions struct {
	// ResponseFormat selects the response shape: "raw" (JSON Schema
	// document, default) or "llm" (a JSON-encoded TOON grammar
	// string). GetDsl returns the body verbatim either way.
	ResponseFormat *OrbitResponseFormatValue `url:"response_format,omitempty"`
}

// OrbitQueryRequest represents the JSON body sent to
// `POST /api/v4/orbit/query`.
//
@@ -309,7 +337,8 @@ type OrbitQueryResult struct {
//
// GitLab API docs: https://docs.gitlab.com/api/orbit/#get-status
func (s *OrbitService) GetStatus(opt *GetOrbitStatusOptions, options ...RequestOptionFunc) (*OrbitStatus, *Response, error) {
	return do[*OrbitStatus](s.client,
	return do[*OrbitStatus](
		s.client,
		withMethod(http.MethodGet),
		withPath("orbit/status"),
		withAPIOpts(opt),
@@ -325,7 +354,8 @@ func (s *OrbitService) GetStatus(opt *GetOrbitStatusOptions, options ...RequestO
//
// GitLab API docs: https://docs.gitlab.com/api/orbit/#get-schema
func (s *OrbitService) GetSchema(opt *GetOrbitSchemaOptions, options ...RequestOptionFunc) (*OrbitSchema, *Response, error) {
	return do[*OrbitSchema](s.client,
	return do[*OrbitSchema](
		s.client,
		withMethod(http.MethodGet),
		withPath("orbit/schema"),
		withAPIOpts(opt),
@@ -341,13 +371,41 @@ func (s *OrbitService) GetSchema(opt *GetOrbitSchemaOptions, options ...RequestO
//
// GitLab API docs: https://docs.gitlab.com/api/orbit/#get-tools
func (s *OrbitService) GetTools(options ...RequestOptionFunc) (*OrbitTools, *Response, error) {
	return do[*OrbitTools](s.client,
	return do[*OrbitTools](
		s.client,
		withMethod(http.MethodGet),
		withPath("orbit/tools"),
		withRequestOpts(options...),
	)
}

// GetDsl returns the Orbit query DSL body verbatim from
// `GET /api/v4/orbit/schema/dsl`.
//
// The DSL surface is in flux during the Orbit beta and is intended
// for agent consumption, so the body is returned as a raw string
// rather than a typed schema. format=raw yields a JSON Schema
// document; format=llm yields a JSON-encoded TOON grammar string.
//
// Note: This API is experimental and may change or be removed in
// future versions.
//
// GitLab API docs: https://docs.gitlab.com/api/orbit/#get-dsl
func (s *OrbitService) GetDsl(opt *GetOrbitDslOptions, options ...RequestOptionFunc) (string, *Response, error) {
	req, err := s.client.NewRequest(http.MethodGet, "orbit/schema/dsl", opt, options)
	if err != nil {
		return "", nil, err
	}

	var buf bytes.Buffer
	resp, err := s.client.Do(req, &buf)
	if err != nil {
		return "", resp, err
	}

	return buf.String(), resp, nil
}

// Query executes an Orbit (Knowledge Graph) query against
// `POST /api/v4/orbit/query`.
//
@@ -369,7 +427,8 @@ func (s *OrbitService) GetTools(options ...RequestOptionFunc) (*OrbitTools, *Res
//
// GitLab API docs: https://docs.gitlab.com/api/orbit/#post-query
func (s *OrbitService) Query(opt *OrbitQueryRequest, options ...RequestOptionFunc) (*OrbitQueryResult, *Response, error) {
	return do[*OrbitQueryResult](s.client,
	return do[*OrbitQueryResult](
		s.client,
		withMethod(http.MethodPost),
		withPath("orbit/query"),
		withAPIOpts(opt),
@@ -508,7 +567,8 @@ type OrbitGraphStatusIndexing struct {
// GitLab API docs:
// https://docs.gitlab.com/api/orbit/#get-graph-status
func (s *OrbitService) GetGraphStatus(opt *GetGraphStatusOptions, options ...RequestOptionFunc) (*OrbitGraphStatus, *Response, error) {
	return do[*OrbitGraphStatus](s.client,
	return do[*OrbitGraphStatus](
		s.client,
		withMethod(http.MethodGet),
		withPath("orbit/graph_status"),
		withAPIOpts(opt),
+44 −2
Original line number Diff line number Diff line
@@ -231,13 +231,54 @@ func TestOrbitService_GetTools(t *testing.T) {
	require.NotNil(t, resp)
	require.Len(t, tools.Tools, 2)
	assert.Equal(t, "query_graph", tools.Tools[0].Name)
	assert.JSONEq(t,
	assert.JSONEq(
		t,
		`{"type": "object", "properties": {"query": {}}}`,
		string(tools.Tools[0].Parameters),
	)
	assert.Equal(t, "get_graph_schema", tools.Tools[1].Name)
}

func TestOrbitService_GetDsl_RawFormat(t *testing.T) {
	t.Parallel()
	// GIVEN a DSL endpoint returning a JSON Schema body
	mux, client := setup(t)

	body := `{"$schema":"https://json-schema.org/draft/2020-12/schema","title":"QueryDSL","type":"object"}`
	mux.HandleFunc("/api/v4/orbit/schema/dsl", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodGet)
		fmt.Fprint(w, body)
	})

	// WHEN GetDsl is called
	dsl, resp, err := client.Orbit.GetDsl(nil)

	// THEN the body is returned verbatim as a string
	require.NoError(t, err)
	require.NotNil(t, resp)
	assert.Equal(t, body, dsl)
}

func TestOrbitService_GetDsl_LLMFormat(t *testing.T) {
	t.Parallel()
	// GIVEN a DSL endpoint returning a JSON-encoded TOON string for llm
	mux, client := setup(t)

	body := `"QueryDSL v2.1.0:\nquery_type: traversal | search"`
	mux.HandleFunc("/api/v4/orbit/schema/dsl", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodGet)
		assert.Equal(t, "llm", r.URL.Query().Get("response_format"))
		fmt.Fprint(w, body)
	})

	// WHEN GetDsl is called with format=llm
	dsl, _, err := client.Orbit.GetDsl(&GetOrbitDslOptions{ResponseFormat: Ptr(OrbitResponseFormatLLM)})

	// THEN the body is returned verbatim
	require.NoError(t, err)
	assert.Equal(t, body, dsl)
}

func TestOrbitService_Query(t *testing.T) {
	t.Parallel()
	// GIVEN an Orbit query endpoint that echoes back a structured result
@@ -289,7 +330,8 @@ func TestOrbitService_Query(t *testing.T) {
	assert.Equal(t, "traversal", result.QueryType)
	assert.Equal(t, []string{"SELECT ..."}, result.RawQueryStrings)
	assert.Equal(t, int64(2), result.RowCount)
	assert.JSONEq(t,
	assert.JSONEq(
		t,
		`[{"_id": "1", "_type": "Project", "name": "alpha"}, {"_id": "2", "_type": "Project", "name": "beta"}]`,
		string(result.Result),
	)
+45 −0
Original line number Diff line number Diff line
@@ -40,6 +40,51 @@ func (m *MockOrbitServiceInterface) EXPECT() *MockOrbitServiceInterfaceMockRecor
	return m.recorder
}

// GetDsl mocks base method.
func (m *MockOrbitServiceInterface) GetDsl(opt *gitlab.GetOrbitDslOptions, options ...gitlab.RequestOptionFunc) (string, *gitlab.Response, error) {
	m.ctrl.T.Helper()
	varargs := []any{opt}
	for _, a := range options {
		varargs = append(varargs, a)
	}
	ret := m.ctrl.Call(m, "GetDsl", varargs...)
	ret0, _ := ret[0].(string)
	ret1, _ := ret[1].(*gitlab.Response)
	ret2, _ := ret[2].(error)
	return ret0, ret1, ret2
}

// GetDsl indicates an expected call of GetDsl.
func (mr *MockOrbitServiceInterfaceMockRecorder) GetDsl(opt any, options ...any) *MockOrbitServiceInterfaceGetDslCall {
	mr.mock.ctrl.T.Helper()
	varargs := append([]any{opt}, options...)
	call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDsl", reflect.TypeOf((*MockOrbitServiceInterface)(nil).GetDsl), varargs...)
	return &MockOrbitServiceInterfaceGetDslCall{Call: call}
}

// MockOrbitServiceInterfaceGetDslCall wrap *gomock.Call
type MockOrbitServiceInterfaceGetDslCall struct {
	*gomock.Call
}

// Return rewrite *gomock.Call.Return
func (c *MockOrbitServiceInterfaceGetDslCall) Return(arg0 string, arg1 *gitlab.Response, arg2 error) *MockOrbitServiceInterfaceGetDslCall {
	c.Call = c.Call.Return(arg0, arg1, arg2)
	return c
}

// Do rewrite *gomock.Call.Do
func (c *MockOrbitServiceInterfaceGetDslCall) Do(f func(*gitlab.GetOrbitDslOptions, ...gitlab.RequestOptionFunc) (string, *gitlab.Response, error)) *MockOrbitServiceInterfaceGetDslCall {
	c.Call = c.Call.Do(f)
	return c
}

// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockOrbitServiceInterfaceGetDslCall) DoAndReturn(f func(*gitlab.GetOrbitDslOptions, ...gitlab.RequestOptionFunc) (string, *gitlab.Response, error)) *MockOrbitServiceInterfaceGetDslCall {
	c.Call = c.Call.DoAndReturn(f)
	return c
}

// GetGraphStatus mocks base method.
func (m *MockOrbitServiceInterface) GetGraphStatus(opt *gitlab.GetGraphStatusOptions, options ...gitlab.RequestOptionFunc) (*gitlab.OrbitGraphStatus, *gitlab.Response, error) {
	m.ctrl.T.Helper()