Skip to content

Commit 3ee834f

Browse files
Merge pull request #710 from apigee/issue709
feat: LLM Operations and Token in API Product config
2 parents d50d7ec + 74f790a commit 3ee834f

File tree

5 files changed

+115
-4
lines changed

5 files changed

+115
-4
lines changed

internal/client/products/products.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ type APIProduct struct {
5858
Scopes []string `json:"scopes,omitempty"`
5959
QuotaCounterScope string `json:"quotaCounterScope,omitempty"`
6060
Space string `json:"space,omitempty"`
61+
LlmQuota string `json:"llmQuota,omitempty"`
62+
LlmQuotaInterval string `json:"llmQuotaInterval,omitempty"`
63+
LlmQuotaTimeUnit string `json:"llmQuotaTimeUnit,omitempty"`
64+
LlmOperationGroup *LlmOperationGroup `json:"llmOperationGroup,omitempty"`
6165
}
6266

6367
type OperationGroup struct {
@@ -72,7 +76,10 @@ type GraphqlOperationGroup struct {
7276

7377
type GrpcOperationGroup struct {
7478
OperationConfigs []grpcOperationConfig `json:"operationConfigs,omitempty"`
75-
OperationConfigType string `json:"operationConfigType,omitempty"`
79+
}
80+
81+
type LlmOperationGroup struct {
82+
OperationConfigs []llmOperationConfig `json:"operationConfigs,omitempty"`
7683
}
7784

7885
type operationConfig struct {
@@ -97,6 +104,13 @@ type grpcOperationConfig struct {
97104
Attributes []Attribute `json:"attributes,omitempty"`
98105
}
99106

107+
type llmOperationConfig struct {
108+
APISource string `json:"apiSource,omitempty"`
109+
Operations []llmOperation `json:"llmOperations,omitempty"`
110+
Quota *quota `json:"llmTokenQuota,omitempty"`
111+
Attributes []Attribute `json:"attributes,omitempty"`
112+
}
113+
100114
type operation struct {
101115
Resource string `json:"resource,omitempty"`
102116
Methods []string `json:"methods,omitempty"`
@@ -107,6 +121,12 @@ type graphQLoperation struct {
107121
Operation string `json:"operation,omitempty"`
108122
}
109123

124+
type llmOperation struct {
125+
Resource string `json:"resource,omitempty"`
126+
Methods []string `json:"methods,omitempty"`
127+
Model string `json:"model,omitempty"`
128+
}
129+
110130
type quota struct {
111131
Limit string `json:"limit,omitempty"`
112132
Interval string `json:"interval,omitempty"`

internal/cmd/products/crtprod.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,14 @@ var CreateCmd = &cobra.Command{
6868
return nil
6969
}
7070

71+
p.LlmQuota = llmQuota
72+
p.LlmQuotaInterval = llmQuotaInterval
73+
p.LlmQuotaTimeUnit = llmQuotaUnit
74+
p.LlmOperationGroup, err = getLlmOperationGroup(llmOperationGroupFile)
75+
if err != nil {
76+
return nil
77+
}
78+
7179
p.Attributes = getAttributes(attrs)
7280

7381
if quotaCounterScope != "" {
@@ -82,10 +90,12 @@ var CreateCmd = &cobra.Command{
8290
` + GetExample(0) + `
8391
8492
Create an API product, using externally defined operations, with auto approval and access=public, and a quota of 100/minute:
85-
` + GetExample(1),
93+
` + GetExample(1)+ `
94+
Create an API product, using externally defined LLM operations, with auto approval and access=public, and an LLM quota of 1000/minute:
95+
` + GetExample(5),
8696
}
8797

88-
var operationGroupFile, gqlOperationGroupFile, grpcOperationGroupFile, quotaCounterScope string
98+
var operationGroupFile, gqlOperationGroupFile, grpcOperationGroupFile, llmOperationGroupFile, quotaCounterScope string
8999

90100
func init() {
91101
CreateCmd.Flags().StringVarP(&name, "name", "n",
@@ -120,6 +130,14 @@ func init() {
120130
"", "Scope of the quota decides how the quota counter gets applied; can be PROXY or OPERATION")
121131
CreateCmd.Flags().StringVarP(&space, "space", "",
122132
"", "Apigee Space to associate to")
133+
CreateCmd.Flags().StringVarP(&llmQuota, "llm-quota", "",
134+
"", "LLM Quota Amount")
135+
CreateCmd.Flags().StringVarP(&llmQuotaInterval, "llm-quota-interval", "",
136+
"", "LLM Quota Interval")
137+
CreateCmd.Flags().StringVarP(&llmQuotaUnit, "llm-quota-timeunit", "",
138+
"", "LLM Quota Unit")
139+
CreateCmd.Flags().StringVarP(&llmOperationGroupFile, "llmopgrp", "",
140+
"", "File containing LLM Operation Group JSON. See samples for how to create the file")
123141
// TODO: apiresource -r later
124142

125143
_ = CreateCmd.MarkFlagRequired("name")

internal/cmd/products/products.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ var (
3737
)
3838

3939
var (
40-
description, approval, displayName, quota, quotaInterval, quotaUnit, space string
40+
description, approval, displayName, quota, quotaInterval, quotaUnit, llmQuota, llmQuotaInterval, llmQuotaUnit, space string
4141
environments, proxies, scopes []string
4242
attrs map[string]string
4343
)
@@ -61,6 +61,16 @@ var examples = []string{
6161
`apigeecli products import -f samples/apiproduct-legacy.json --default-token`,
6262
`apigeecli products import -f samples/apiproduct-gqlgroup.json --default-token`,
6363
`apigeecli products import -f samples/apiproduct-op-group.json --default-token`,
64+
`apigeecli products create --name $product_name \
65+
--display-name $product_name \
66+
--llmopgrp $ops_file \
67+
--llm-quota=1000 \
68+
--llm-quota-interval=1 \
69+
--llm-quota-timeunit=minute \
70+
--envs $env \
71+
--space $space \
72+
--approval auto \
73+
--attrs access=public --default-token`,
6474
}
6575

6676
func init() {
@@ -141,6 +151,26 @@ func getGrpcOperationGroup(grpcOperationGroupFile string) (*products.GrpcOperati
141151
return nil, nil
142152
}
143153

154+
func getLlmOperationGroup(llmOperationGroupFile string) (*products.LlmOperationGroup, error) {
155+
var llmOperationGrpBytes []byte
156+
var err error
157+
158+
llmOperationGrp := products.LlmOperationGroup{}
159+
160+
if llmOperationGroupFile != "" {
161+
if llmOperationGrpBytes, err = os.ReadFile(llmOperationGroupFile); err != nil {
162+
clilog.Debug.Println(err)
163+
return nil, err
164+
}
165+
if err = json.Unmarshal(llmOperationGrpBytes, &llmOperationGrp); err != nil {
166+
clilog.Debug.Println(err)
167+
return nil, err
168+
}
169+
return &llmOperationGrp, nil
170+
}
171+
return nil, nil
172+
}
173+
144174
func getAttributes(attrs map[string]string) []products.Attribute {
145175
var attributes []products.Attribute
146176

internal/cmd/products/updprod.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,14 @@ var UpdateCmd = &cobra.Command{
6868
return nil
6969
}
7070

71+
p.LlmQuota = llmQuota
72+
p.LlmQuotaInterval = llmQuotaInterval
73+
p.LlmQuotaTimeUnit = llmQuotaUnit
74+
p.LlmOperationGroup, err = getLlmOperationGroup(llmOperationGroupFile)
75+
if err != nil {
76+
return nil
77+
}
78+
7179
p.Attributes = getAttributes(attrs)
7280

7381
if quotaCounterScope != "" {
@@ -113,6 +121,14 @@ func init() {
113121
"", "Scope of the quota decides how the quota counter gets applied; can be PROXY or OPERATION")
114122
UpdateCmd.Flags().StringVarP(&space, "space", "",
115123
"", "Associated Apigee Space. Pass this if the API Product being updated is part of a space")
124+
UpdateCmd.Flags().StringVarP(&llmQuota, "llm-quota", "",
125+
"", "LLM Quota Amount")
126+
UpdateCmd.Flags().StringVarP(&llmQuotaInterval, "llm-quota-interval", "",
127+
"", "LLM Quota Interval")
128+
UpdateCmd.Flags().StringVarP(&llmQuotaUnit, "llm-quota-timeunit", "",
129+
"", "LLM Quota Unit")
130+
UpdateCmd.Flags().StringVarP(&llmOperationGroupFile, "llmopgrp", "",
131+
"", "File containing LLM Operation Group JSON. See samples for how to create the file")
116132
// TODO: apiresource -r later
117133

118134
_ = UpdateCmd.MarkFlagRequired("name")

test/apiproduct-llmop-group.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"operationConfigs": [
3+
{
4+
"apiSource": "httpbin",
5+
"llmOperations": [
6+
{
7+
"resource": "/httpbin",
8+
"methods": [
9+
"POST"
10+
],
11+
"model": "gemini-2.5-flash"
12+
}
13+
],
14+
"llmTokenQuota": {
15+
"limit": "100",
16+
"interval": "5",
17+
"timeUnit": "minute"
18+
},
19+
"attributes": [
20+
{
21+
"name": "key1",
22+
"value": "value1"
23+
}
24+
]
25+
}
26+
]
27+
}

0 commit comments

Comments
 (0)