Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "1.2.0"
".": "1.3.0"
}
8 changes: 4 additions & 4 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 249
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-a6fedde02dc6241719ebb2589062ba2892baa8dbe928a2d718643beede85e7b3.yml
openapi_spec_hash: a712e4ee68f829570b3f5b267afa5a05
config_hash: e02ca1082421dfe55b145c45e95d6126
configured_endpoints: 251
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-b5b621065906a2579dc180db1236ee3b08a4fca9539accc2fbbf88da0ca3923f.yml
openapi_spec_hash: 45b1b4692b26e714008d8120ccfc7433
config_hash: ef3ce17315a31703e7af0567b3e9738c
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Changelog

## 1.3.0 (2026-06-17)

Full Changelog: [v1.2.0...v1.3.0](https://github.com/openai/openai-cli/compare/v1.2.0...v1.3.0)

### Features

* **api:** admin spend_alerts ([f183cb0](https://github.com/openai/openai-cli/commit/f183cb04db80e2a89364c0b46b81f355edbeced5))
* **api:** responses.moderation and chat_completions.moderation ([d660d08](https://github.com/openai/openai-cli/commit/d660d0873624f3895d9463ec98e6afc9d63a52b8))
* **api:** update OpenAPI spec or Stainless config ([7aefee4](https://github.com/openai/openai-cli/commit/7aefee4982a088a9299dc68953f0dea796ee5ff5))
* **api:** update OpenAPI spec or Stainless config ([dee1f3e](https://github.com/openai/openai-cli/commit/dee1f3ea2e7dee54aaa44faddd27675d7e44e43d))

## 1.2.0 (2026-06-01)

Full Changelog: [v1.1.2...v1.2.0](https://github.com/openai/openai-cli/compare/v1.1.2...v1.2.0)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ require (
github.com/goccy/go-yaml v1.18.0
github.com/itchyny/json2yaml v0.1.4
github.com/muesli/reflow v0.3.0
github.com/openai/openai-go/v3 v3.38.0
github.com/openai/openai-go/v3 v3.40.0
github.com/stretchr/testify v1.10.0
github.com/tidwall/gjson v1.18.0
github.com/tidwall/pretty v1.2.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
github.com/openai/openai-go/v3 v3.38.0 h1:Kre0Fz9mPUxtWjRB/CoNBHflp9W7FkztOm/XMDr/A3E=
github.com/openai/openai-go/v3 v3.38.0/go.mod h1:cdufnVK14cWcT9qA1rRtrXx4FTRsgbDPW7Ia7SS5cZo=
github.com/openai/openai-go/v3 v3.40.0 h1:nohsDVADU/JFPiwi5bD3G6Eo35CjNKv7Ompqc7H2cmY=
github.com/openai/openai-go/v3 v3.40.0/go.mod h1:cdufnVK14cWcT9qA1rRtrXx4FTRsgbDPW7Ia7SS5cZo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
Expand Down
5 changes: 5 additions & 0 deletions pkg/cmd/adminorganizationadminapikey.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ var adminOrganizationAdminAPIKeysCreate = cli.Command{
Required: true,
BodyPath: "name",
},
&requestflag.Flag[int64]{
Name: "expires-in-seconds",
Usage: "The number of seconds until the API key expires. Omit this field for a key that does not expire.",
BodyPath: "expires_in_seconds",
},
},
Action: handleAdminOrganizationAdminAPIKeysCreate,
HideHelpCommand: true,
Expand Down
5 changes: 4 additions & 1 deletion pkg/cmd/adminorganizationadminapikey_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@ func TestAdminOrganizationAdminAPIKeysCreate(t *testing.T) {
"--admin-api-key", "string",
"admin:organization:admin-api-keys", "create",
"--name", "New Admin Key",
"--expires-in-seconds", "2592000",
)
})

t.Run("piping data", func(t *testing.T) {
// Test piping YAML data over stdin
pipeData := []byte("name: New Admin Key")
pipeData := []byte("" +
"name: New Admin Key\n" +
"expires_in_seconds: 2592000\n")
mocktest.TestRunMockTestWithPipeAndFlags(
t, pipeData,
"--api-key", "string",
Expand Down
8 changes: 7 additions & 1 deletion pkg/cmd/adminorganizationauditlog.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,15 @@ var adminOrganizationAuditLogsList = requestflag.WithInnerFlags(cli.Command{
},
&requestflag.Flag[[]string]{
Name: "resource-id",
Usage: "Return only events performed on these targets. For example, a project ID updated.",
Usage: "Return only events performed on these targets. For example, a project ID updated. For ChatGPT connector role events, use the workspace connector resource ID shown in `details.id`, such as `<workspace_id>__<connector_id>`.",
QueryPath: "resource_ids",
},
&requestflag.Flag[bool]{
Name: "tenant-only",
Usage: "Return only tenant-scoped events associated with this organization. Required for tenant-scoped events such as `role.bound_to_resource` and `role.unbound_from_resource`. When `true`, all supplied event types must be tenant-scoped.",
Default: false,
QueryPath: "tenant_only",
},
&requestflag.Flag[int64]{
Name: "max-items",
Usage: "The maximum number of items to return (use -1 for unlimited).",
Expand Down
2 changes: 2 additions & 0 deletions pkg/cmd/adminorganizationauditlog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func TestAdminOrganizationAuditLogsList(t *testing.T) {
"--limit", "0",
"--project-id", "string",
"--resource-id", "string",
"--tenant-only=true",
)
})

Expand All @@ -52,6 +53,7 @@ func TestAdminOrganizationAuditLogsList(t *testing.T) {
"--limit", "0",
"--project-id", "string",
"--resource-id", "string",
"--tenant-only=true",
)
})
}
71 changes: 71 additions & 0 deletions pkg/cmd/adminorganizationprojectspendalert.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,26 @@ var adminOrganizationProjectsSpendAlertsCreate = requestflag.WithInnerFlags(cli.
},
})

var adminOrganizationProjectsSpendAlertsRetrieve = cli.Command{
Name: "retrieve",
Usage: "Retrieves a project spend alert.",
Suggest: true,
Flags: []cli.Flag{
&requestflag.Flag[string]{
Name: "project-id",
Required: true,
PathParam: "project_id",
},
&requestflag.Flag[string]{
Name: "alert-id",
Required: true,
PathParam: "alert_id",
},
},
Action: handleAdminOrganizationProjectsSpendAlertsRetrieve,
HideHelpCommand: true,
}

var adminOrganizationProjectsSpendAlertsUpdate = requestflag.WithInnerFlags(cli.Command{
Name: "update",
Usage: "Updates a project spend alert.",
Expand Down Expand Up @@ -242,6 +262,57 @@ func handleAdminOrganizationProjectsSpendAlertsCreate(ctx context.Context, cmd *
})
}

func handleAdminOrganizationProjectsSpendAlertsRetrieve(ctx context.Context, cmd *cli.Command) error {
client := openai.NewClient(getDefaultRequestOptions(cmd)...)
unusedArgs := cmd.Args().Slice()
if !cmd.IsSet("project-id") && len(unusedArgs) > 0 {
cmd.Set("project-id", unusedArgs[0])
unusedArgs = unusedArgs[1:]
}
if !cmd.IsSet("alert-id") && len(unusedArgs) > 0 {
cmd.Set("alert-id", unusedArgs[0])
unusedArgs = unusedArgs[1:]
}
if len(unusedArgs) > 0 {
return fmt.Errorf("Unexpected extra arguments: %v", unusedArgs)
}

options, err := flagOptions(
cmd,
apiquery.NestedQueryFormatBrackets,
apiquery.ArrayQueryFormatBrackets,
EmptyBody,
false,
)
if err != nil {
return err
}

var res []byte
options = append(options, option.WithResponseBodyInto(&res))
_, err = client.Admin.Organization.Projects.SpendAlerts.Get(
ctx,
cmd.Value("project-id").(string),
cmd.Value("alert-id").(string),
options...,
)
if err != nil {
return err
}

obj := gjson.ParseBytes(res)
format := cmd.Root().String("format")
explicitFormat := cmd.Root().IsSet("format")
transform := cmd.Root().String("transform")
return ShowJSON(obj, ShowJSONOpts{
ExplicitFormat: explicitFormat,
Format: format,
RawOutput: cmd.Root().Bool("raw-output"),
Title: "admin:organization:projects:spend-alerts retrieve",
Transform: transform,
})
}

func handleAdminOrganizationProjectsSpendAlertsUpdate(ctx context.Context, cmd *cli.Command) error {
client := openai.NewClient(getDefaultRequestOptions(cmd)...)
unusedArgs := cmd.Args().Slice()
Expand Down
13 changes: 13 additions & 0 deletions pkg/cmd/adminorganizationprojectspendalert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,19 @@ func TestAdminOrganizationProjectsSpendAlertsCreate(t *testing.T) {
})
}

func TestAdminOrganizationProjectsSpendAlertsRetrieve(t *testing.T) {
t.Run("regular flags", func(t *testing.T) {
mocktest.TestRunMockTestWithFlags(
t,
"--api-key", "string",
"--admin-api-key", "string",
"admin:organization:projects:spend-alerts", "retrieve",
"--project-id", "project_id",
"--alert-id", "alert_id",
)
})
}

func TestAdminOrganizationProjectsSpendAlertsUpdate(t *testing.T) {
t.Run("regular flags", func(t *testing.T) {
mocktest.TestRunMockTestWithFlags(
Expand Down
57 changes: 57 additions & 0 deletions pkg/cmd/adminorganizationspendalert.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,21 @@ var adminOrganizationSpendAlertsCreate = requestflag.WithInnerFlags(cli.Command{
},
})

var adminOrganizationSpendAlertsRetrieve = cli.Command{
Name: "retrieve",
Usage: "Retrieves an organization spend alert.",
Suggest: true,
Flags: []cli.Flag{
&requestflag.Flag[string]{
Name: "alert-id",
Required: true,
PathParam: "alert_id",
},
},
Action: handleAdminOrganizationSpendAlertsRetrieve,
HideHelpCommand: true,
}

var adminOrganizationSpendAlertsUpdate = requestflag.WithInnerFlags(cli.Command{
Name: "update",
Usage: "Updates an organization spend alert.",
Expand Down Expand Up @@ -214,6 +229,48 @@ func handleAdminOrganizationSpendAlertsCreate(ctx context.Context, cmd *cli.Comm
})
}

func handleAdminOrganizationSpendAlertsRetrieve(ctx context.Context, cmd *cli.Command) error {
client := openai.NewClient(getDefaultRequestOptions(cmd)...)
unusedArgs := cmd.Args().Slice()
if !cmd.IsSet("alert-id") && len(unusedArgs) > 0 {
cmd.Set("alert-id", unusedArgs[0])
unusedArgs = unusedArgs[1:]
}
if len(unusedArgs) > 0 {
return fmt.Errorf("Unexpected extra arguments: %v", unusedArgs)
}

options, err := flagOptions(
cmd,
apiquery.NestedQueryFormatBrackets,
apiquery.ArrayQueryFormatBrackets,
EmptyBody,
false,
)
if err != nil {
return err
}

var res []byte
options = append(options, option.WithResponseBodyInto(&res))
_, err = client.Admin.Organization.SpendAlerts.Get(ctx, cmd.Value("alert-id").(string), options...)
if err != nil {
return err
}

obj := gjson.ParseBytes(res)
format := cmd.Root().String("format")
explicitFormat := cmd.Root().IsSet("format")
transform := cmd.Root().String("transform")
return ShowJSON(obj, ShowJSONOpts{
ExplicitFormat: explicitFormat,
Format: format,
RawOutput: cmd.Root().Bool("raw-output"),
Title: "admin:organization:spend-alerts retrieve",
Transform: transform,
})
}

func handleAdminOrganizationSpendAlertsUpdate(ctx context.Context, cmd *cli.Command) error {
client := openai.NewClient(getDefaultRequestOptions(cmd)...)
unusedArgs := cmd.Args().Slice()
Expand Down
12 changes: 12 additions & 0 deletions pkg/cmd/adminorganizationspendalert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ func TestAdminOrganizationSpendAlertsCreate(t *testing.T) {
})
}

func TestAdminOrganizationSpendAlertsRetrieve(t *testing.T) {
t.Run("regular flags", func(t *testing.T) {
mocktest.TestRunMockTestWithFlags(
t,
"--api-key", "string",
"--admin-api-key", "string",
"admin:organization:spend-alerts", "retrieve",
"--alert-id", "alert_id",
)
})
}

func TestAdminOrganizationSpendAlertsUpdate(t *testing.T) {
t.Run("regular flags", func(t *testing.T) {
mocktest.TestRunMockTestWithFlags(
Expand Down
12 changes: 12 additions & 0 deletions pkg/cmd/chatcompletion.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ var chatCompletionsCreate = requestflag.WithInnerFlags(cli.Command{
Usage: "Output types that you would like the model to generate.\nMost models are capable of generating text, which is the default:\n\n`[\"text\"]`\n\nThe `gpt-4o-audio-preview` model can also be used to\n[generate audio](https://platform.openai.com/docs/guides/audio). To request that this model generate\nboth text and audio responses, you can use:\n\n`[\"text\", \"audio\"]`\n",
BodyPath: "modalities",
},
&requestflag.Flag[map[string]any]{
Name: "moderation",
Usage: "Configuration for running moderation on the request input and generated output.\n",
BodyPath: "moderation",
},
&requestflag.Flag[*int64]{
Name: "n",
Usage: "How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the choices. Keep `n` as `1` to minimize costs.",
Expand Down Expand Up @@ -245,6 +250,13 @@ var chatCompletionsCreate = requestflag.WithInnerFlags(cli.Command{
InnerField: "parameters",
},
},
"moderation": {
&requestflag.InnerFlag[string]{
Name: "moderation.model",
Usage: "The moderation model to use for moderated completions, e.g. 'omni-moderation-latest'.",
InnerField: "model",
},
},
"prediction": {
&requestflag.InnerFlag[any]{
Name: "prediction.content",
Expand Down
4 changes: 4 additions & 0 deletions pkg/cmd/chatcompletion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func TestChatCompletionsCreate(t *testing.T) {
"--max-tokens", "0",
"--metadata", "{foo: string}",
"--modality", "[text]",
"--moderation", "{model: model}",
"--n", "1",
"--parallel-tool-calls=true",
"--prediction", "{content: string, type: content}",
Expand Down Expand Up @@ -81,6 +82,7 @@ func TestChatCompletionsCreate(t *testing.T) {
"--max-tokens", "0",
"--metadata", "{foo: string}",
"--modality", "[text]",
"--moderation.model", "model",
"--n", "1",
"--parallel-tool-calls=true",
"--prediction.content", "string",
Expand Down Expand Up @@ -137,6 +139,8 @@ func TestChatCompletionsCreate(t *testing.T) {
" foo: string\n" +
"modalities:\n" +
" - text\n" +
"moderation:\n" +
" model: model\n" +
"'n': 1\n" +
"parallel_tool_calls: true\n" +
"prediction:\n" +
Expand Down
2 changes: 2 additions & 0 deletions pkg/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,7 @@ func init() {
Suggest: true,
Commands: []*cli.Command{
&adminOrganizationSpendAlertsCreate,
&adminOrganizationSpendAlertsRetrieve,
&adminOrganizationSpendAlertsUpdate,
&adminOrganizationSpendAlertsList,
&adminOrganizationSpendAlertsDelete,
Expand Down Expand Up @@ -670,6 +671,7 @@ func init() {
Suggest: true,
Commands: []*cli.Command{
&adminOrganizationProjectsSpendAlertsCreate,
&adminOrganizationProjectsSpendAlertsRetrieve,
&adminOrganizationProjectsSpendAlertsUpdate,
&adminOrganizationProjectsSpendAlertsList,
&adminOrganizationProjectsSpendAlertsDelete,
Expand Down
5 changes: 5 additions & 0 deletions pkg/cmd/inputtoken.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ var responsesInputTokensCount = requestflag.WithInnerFlags(cli.Command{
HideHelpCommand: true,
}, map[string][]requestflag.HasOuterFlag{
"reasoning": {
&requestflag.InnerFlag[*string]{
Name: "reasoning.context",
Usage: "Controls which reasoning items are rendered back to the model on later turns.\nWhen returned on a response, this is the effective reasoning context mode\nused for the response.\n",
InnerField: "context",
},
&requestflag.InnerFlag[*string]{
Name: "reasoning.effort",
Usage: "Constrains effort on reasoning for\n[reasoning models](https://platform.openai.com/docs/guides/reasoning).\nCurrently supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. Reducing\nreasoning effort can result in faster responses and fewer tokens used\non reasoning in a response.\n\n- `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool calls are supported for all reasoning values in gpt-5.1.\n- All models before `gpt-5.1` default to `medium` reasoning effort, and do not support `none`.\n- The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort.\n- `xhigh` is supported for all models after `gpt-5.1-codex-max`.\n",
Expand Down
Loading
Loading