diff --git a/.changesets/1791385151-7d8442f0.yaml b/.changesets/1791385151-7d8442f0.yaml new file mode 100644 index 000000000..4839e0256 --- /dev/null +++ b/.changesets/1791385151-7d8442f0.yaml @@ -0,0 +1,10 @@ +id: 1791385151-7d8442f0 +features: + - cliCommands +targets: + - cli +type: feat +bump: patch +description: report selected stream metadata on stderr +author: ThomasRooney +date: "2026-10-07" diff --git a/internal/extensions/cli_commands.go b/internal/extensions/cli_commands.go index 24ec9a9f3..37fb26a02 100644 --- a/internal/extensions/cli_commands.go +++ b/internal/extensions/cli_commands.go @@ -10,6 +10,7 @@ import ( "strconv" "strings" "time" + "unicode" "github.com/speakeasy-api/openapi-generation/v2/internal/document" "github.com/speakeasy-api/openapi-generation/v2/pkg/errors" @@ -214,14 +215,21 @@ type CLICommandArtifact struct { explicitBindings map[string]bool } +type CLICommandStreamMetadata struct { + Select string `json:"select" yaml:"select"` + Pointer string `json:"pointer" yaml:"pointer"` + Label string `json:"label" yaml:"label"` +} + // CLICommandStreamProjection selects the field of each streamed event whose // string value is written raw to stdout as the event arrives (stream mode // only). Select is the authored singular JSONPath from the event root as the // CLI sees each event (the same root a per-event --jq filter sees); Pointer // is its RFC 6901 lowering, which the generated runtime evaluates. type CLICommandStreamProjection struct { - Select string `json:"select" yaml:"select"` - Pointer string `json:"pointer" yaml:"pointer"` + Metadata *CLICommandStreamMetadata `json:"metadata,omitempty" yaml:"metadata,omitempty"` + Select string `json:"select" yaml:"select"` + Pointer string `json:"pointer" yaml:"pointer"` } // CLICommandOutput groups output behavior for a declared command. @@ -515,7 +523,7 @@ var cliCommandKeys = []string{ var cliOutputKeys = []string{"artifact", "stream"} -var cliOutputStreamKeys = []string{"select"} +var cliOutputStreamKeys = []string{"select", "metadata"} var cliOperationKeys = []string{"output", "flags"} @@ -2225,6 +2233,13 @@ func (d *cliManifestDecoder) decodeStreamProjection(cmdKey string, node *yaml.No } stream.Select = raw stream.Pointer = cliSegmentsToPointer(segments) + case "metadata": + metadata, err := d.decodeStreamMetadata(entry.Value) + if err != nil { + return nil, fmt.Errorf("command %q: %w", cmdKey, err) + } + stream.Metadata = metadata + default: return nil, fmt.Errorf("line %d: command %q output.stream has unknown key %q%s", entry.Key.Line, cmdKey, entry.Key.Value, cliDidYouMean(entry.Key.Value, cliOutputStreamKeys)) } @@ -2443,3 +2458,43 @@ func cliMapKeys(m map[string]bool) []string { } return keys } + +func (d *cliManifestDecoder) decodeStreamMetadata(node *yaml.Node) (*CLICommandStreamMetadata, error) { + entries, err := cliMapEntries(node, "output.stream.metadata") + if err != nil { + return nil, err + } + metadata := &CLICommandStreamMetadata{} + for _, entry := range entries { + switch entry.Key.Value { + case "select": + value, err := cliScalarString(entry.Value, "output.stream.metadata.select") + if err != nil { + return nil, err + } + segments, err := cliParseSingularPath(value) + if err != nil { + return nil, fmt.Errorf("line %d: output.stream.metadata.select: %w", entry.Value.Line, err) + } + metadata.Select = value + metadata.Pointer = cliSegmentsToPointer(segments) + case "label": + value, err := cliScalarString(entry.Value, "output.stream.metadata.label") + if err != nil { + return nil, err + } + for _, r := range value { + if !unicode.IsPrint(r) { + return nil, fmt.Errorf("line %d: output.stream.metadata.label must contain only printable characters", entry.Value.Line) + } + } + metadata.Label = value + default: + return nil, fmt.Errorf("line %d: output.stream.metadata has unknown key %q", entry.Key.Line, entry.Key.Value) + } + } + if metadata.Select == "" || strings.TrimSpace(metadata.Label) == "" { + return nil, fmt.Errorf("line %d: output.stream.metadata requires nonempty select and label", node.Line) + } + return metadata, nil +} diff --git a/internal/extensions/cli_commands_link.go b/internal/extensions/cli_commands_link.go index 9db65297f..697779f1f 100644 --- a/internal/extensions/cli_commands_link.go +++ b/internal/extensions/cli_commands_link.go @@ -1745,12 +1745,22 @@ func (d *cliManifestDecoder) linkStreamProjection(owner string, stream *CLIComma if !opInfo.streamMediaSeen { return fmt.Errorf("%s declares output.stream, but operation %q has no streaming (text/event-stream or JSONL) success response; the CLI only streams events for operations that declare one", owner, opID) } - segments, err := cliParseSingularPath(stream.Select) + if err := d.linkStreamSelection(owner, "output.stream.select", stream.Select, opInfo); err != nil { + return err + } + if stream.Metadata != nil { + return d.linkStreamSelection(owner, "output.stream.metadata.select", stream.Metadata.Select, opInfo) + } + return nil +} + +func (d *cliManifestDecoder) linkStreamSelection(owner, field, selectPath string, opInfo *cliOperationInfo) error { + segments, err := cliParseSingularPath(selectPath) if err != nil { - return fmt.Errorf("%s output.stream.select: %w", owner, err) + return fmt.Errorf("%s %s: %w", owner, field, err) } - walker := &cliStreamPathWalker{d: d, owner: owner, selectPath: stream.Select} + walker := &cliStreamPathWalker{d: d, owner: owner, selectPath: selectPath, field: field} for _, schema := range opInfo.streamSchemas { if schema == nil { walker.unverifiable("the streaming response declares no schema") @@ -1763,16 +1773,16 @@ func (d *cliManifestDecoder) linkStreamProjection(owner string, stream *CLIComma } if walker.resolved == 0 { if walker.unverified == 0 { - return fmt.Errorf("%s output.stream.select %s does not resolve in any event shape of the streaming response%s", owner, stream.Select, walker.missSuggestion()) + return fmt.Errorf("%s %s %s does not resolve in any event shape of the streaming response%s", owner, field, selectPath, walker.missSuggestion()) } - d.warnf("%s output.stream.select %s could not be verified against the streaming response schema (%s); events without a string at that path are skipped at runtime", owner, stream.Select, walker.firstReason) + d.warnf("%s %s %s could not be verified against the streaming response schema (%s); events without a string at that path are skipped at runtime", owner, field, selectPath, walker.firstReason) return nil } - if err := d.lintProjection(owner, "output.stream.select", cliSingularPathToJQ(segments), "the streaming response declares no event schema", cliOperationProjectionSchema(opInfo), true); err != nil { + if err := d.lintProjection(owner, field, cliSingularPathToJQ(segments), "the streaming response declares no event schema", cliOperationProjectionSchema(opInfo), true); err != nil { return err } if walker.unverified > 0 { - d.warnf("%s output.stream.select %s resolves in %d event shape(s) but could not be verified in every arm (%s); unverified events without a string at that path are skipped at runtime", owner, stream.Select, walker.resolved, walker.firstReason) + d.warnf("%s %s %s resolves in %d event shape(s) but could not be verified in every arm (%s); unverified events without a string at that path are skipped at runtime", owner, field, selectPath, walker.resolved, walker.firstReason) } return nil } @@ -1804,6 +1814,7 @@ type cliStreamPathWalker struct { d *cliManifestDecoder owner string selectPath string + field string resolved int // arms where the full path resolved to a string/null leaf unverified int // arms the walk could not see through @@ -1881,7 +1892,7 @@ func (w *cliStreamPathWalker) walk(schema any, segments []cliPathSegment, seen [ } component, ok := w.d.schemaIndex.components[name] if !ok { - w.err = fmt.Errorf("%s output.stream.select %s: referenced schema %q does not exist in components.schemas%s", w.owner, w.selectPath, name, cliDidYouMean(name, cliComponentNames(w.d.schemaIndex.components))) + w.err = fmt.Errorf("%s %s %s: referenced schema %q does not exist in components.schemas%s", w.owner, w.field, w.selectPath, name, cliDidYouMean(name, cliComponentNames(w.d.schemaIndex.components))) return } w.walk(component, segments, append(seen, name)) @@ -2016,7 +2027,11 @@ func (w *cliStreamPathWalker) checkLeaf(schemaMap map[string]any, seen []string) case leafString: w.resolved++ case leafOther: - w.err = fmt.Errorf("%s output.stream.select %s resolves to %s in one event shape; the streamed projection writes string values raw, so select must address a string field", w.owner, w.selectPath, kind) + if w.field == "output.stream.metadata.select" { + w.err = fmt.Errorf("%s %s %s resolves to %s in one event shape; metadata must address a string field", w.owner, w.field, w.selectPath, kind) + } else { + w.err = fmt.Errorf("%s %s %s resolves to %s in one event shape; the streamed projection writes string values raw, so select must address a string field", w.owner, w.field, w.selectPath, kind) + } default: w.unverifiable("the selected field is untyped") } diff --git a/internal/extensions/cli_commands_test.go b/internal/extensions/cli_commands_test.go index ad359379e..efacfae0f 100644 --- a/internal/extensions/cli_commands_test.go +++ b/internal/extensions/cli_commands_test.go @@ -5319,3 +5319,68 @@ commands: assert.Empty(t, background.DefaultFrom) assert.Nil(t, background.Default) } + +func TestCLICommands_StreamMetadata(t *testing.T) { + manifest, _, err := decodeCLITest(t, ` +version: 1 +commands: + say: + op: StreamTask + output: + stream: + select: $.data.delta.text + metadata: + select: $.data.error.message + label: Resource ID +`) + require.NoError(t, err) + metadata := manifest.Commands[0].Output.Stream.Metadata + require.NotNil(t, metadata) + assert.Equal(t, "$.data.error.message", metadata.Select) + assert.Equal(t, "/data/error/message", metadata.Pointer) + assert.Equal(t, "Resource ID", metadata.Label) +} + +func TestCLICommands_StreamMetadataValidation(t *testing.T) { + for _, tc := range []struct{ name, metadata, want string }{ + {"missing select", "{label: ID}", "requires nonempty select and label"}, + {"missing label", "{select: $.data.error.message}", "requires nonempty select and label"}, + {"empty label", "{select: $.data.error.message, label: ' '}", "requires nonempty select and label"}, + {"label type", "{select: $.data.error.message, label: 12}", "metadata.label"}, + {"select type", "{select: [], label: ID}", "metadata.select"}, + {"unknown key", "{select: $.data.error.message, label: ID, labels: ID}", "metadata has unknown key"}, + {"wildcard", "{select: '$.data[*]', label: ID}", "metadata.select"}, + {"absent path", "{select: $.data.missing, label: ID}", "output.stream.metadata.select $.data.missing does not resolve"}, + {"number", "{select: $.data.index, label: ID}", "output.stream.metadata.select $.data.index resolves to an integer"}, + {"object", "{select: $.data.delta, label: ID}", "output.stream.metadata.select $.data.delta resolves to an object"}, + {"newline label", `{select: $.data.error.message, label: "ID\nInjected"}`, "metadata.label must contain only printable"}, + {"escape label", `{select: $.data.error.message, label: "ID\x1b"}`, "metadata.label must contain only printable"}, + {"bidi label", `{select: $.data.error.message, label: "ID\u202e"}`, "metadata.label must contain only printable"}, + {"separator label", `{select: $.data.error.message, label: "ID\u2028"}`, "metadata.label must contain only printable"}, + } { + t.Run(tc.name, func(t *testing.T) { + requireDecodeError(t, "version: 1\ncommands:\n say:\n op: StreamTask\n output:\n stream:\n select: $.data.delta.text\n metadata: "+tc.metadata+"\n", tc.want) + }) + } +} + +func TestCLICommands_StreamMetadataOpenSchema(t *testing.T) { + manifest, warnings, err := decodeCLITest(t, ` +version: 1 +operations: + StreamTaskLines: + output: + stream: + select: $.text + metadata: + select: $['resource/id~key'] + label: Resource ID +`) + require.NoError(t, err) + require.Len(t, manifest.Operations, 1) + require.NotNil(t, manifest.Operations[0].Output.Stream.Metadata) + assert.Equal(t, "/resource~1id~0key", manifest.Operations[0].Output.Stream.Metadata.Pointer) + require.Len(t, warnings, 2) + assert.Contains(t, warnings[1], "output.stream.metadata.select") + assert.Contains(t, warnings[1], "could not be verified") +} diff --git a/scripts/build-review-sdk.sh b/scripts/build-review-sdk.sh index d51df45b1..9ae62e2c1 100755 --- a/scripts/build-review-sdk.sh +++ b/scripts/build-review-sdk.sh @@ -30,8 +30,13 @@ mkdir -p ./zSDKs/sdk-$TARGET/.speakeasy/testfiles cp ./tests/tests/review/testfiles/postfiletest.txt ./zSDKs/sdk-$TARGET/.speakeasy/testfiles/postfiletest.txt tmp_tests="$(mktemp "./zSDKs/sdk-$TARGET/.speakeasy/tests.arazzo.yaml.XXXXXX.tmp")" +tmp_spec_base="" +tmp_spec="" cleanup() { rm -f "$tmp_tests" + if [[ -n "$tmp_spec_base" ]]; then + rm -f "$tmp_spec_base" "${tmp_spec_base}.yaml" + fi } trap cleanup EXIT @@ -75,7 +80,16 @@ rm -rf "./testprojects/$TARGET" || true EXTRA_ARGS="${EXTRA_ARGS:-} ${*:2}" print_msg_with_ctx "${BUILD_ICON} {green}{bold}Building SDK{reset}" "target=${TARGET}|variant=review|args=${EXTRA_ARGS}" -run_cmd go run cmd/generate/main.go -s ./tests/specs/review.yaml -o ./zSDKs/sdk-$TARGET -l $TARGET --validate-integrity ${EXTRA_ARGS} +review_spec="./tests/specs/review.yaml" +review_overlay="./tests/overlays/review/$TARGET/overlay.yaml" +if [[ -f "$review_overlay" ]]; then + # Keep the resolved spec beside its source so relative references still resolve. + tmp_spec_base="$(mktemp "./tests/specs/review.${TARGET}.XXXXXXXX")" + tmp_spec="${tmp_spec_base}.yaml" + go run ./cmd/overlay -s "$review_spec" -overlay "$review_overlay" -out "$tmp_spec" + review_spec="$tmp_spec" +fi +run_cmd go run cmd/generate/main.go -s "$review_spec" -o ./zSDKs/sdk-$TARGET -l $TARGET --validate-integrity ${EXTRA_ARGS} # Copy gen.yaml back to source folder after successful build cp ./zSDKs/sdk-$TARGET/.speakeasy/gen.yaml ./tests/config/review/$TARGET/.speakeasy/gen.yaml diff --git a/templates/perms.go b/templates/perms.go index 7c796bbd6..43a4d6f22 100644 --- a/templates/perms.go +++ b/templates/perms.go @@ -211,6 +211,7 @@ var fileMode = map[string]fs.FileMode{ "templates/cli/tests/primary/retries_test.go.stmpl": 0o644, "templates/cli/tests/primary/security_ranking_test.go.stmpl": 0o644, "templates/cli/tests/primary/servers_test.go.stmpl": 0o644, + "templates/cli/tests/primary/streammetadata_additional_test.go.stmpl": 0o644, "templates/cli/tests/primary/stringconstraints_test.go.stmpl": 0o644, "templates/cli/tests/primary/table_additional_test.go.stmpl": 0o644, "templates/cli/tests/primary/telemetry_test.go.stmpl": 0o644, diff --git a/templates/templates/cli/README.md b/templates/templates/cli/README.md index beedc9c7b..ca2a27dce 100644 --- a/templates/templates/cli/README.md +++ b/templates/templates/cli/README.md @@ -1022,6 +1022,23 @@ Contract (settled in design review): - Applies only when the user has not chosen a rendering: an explicit `--output-format` (flag, env, or config — `outputFormatExplicit`) or a user `--jq` keeps the existing per-event rendering (NDJSON under `json`, jq results, YAML/TOON). Implicit defaults — pretty, or agent mode's TOON — yield to the projection; a manifest `output.jq` default is not a user choice and also yields in stream mode. - The write path is unbuffered end to end: cobra `OutOrStdout()` → `os.Stdout` (a `write(2)` per event); the SDK `EventStream` scanner returns each event as soon as its boundary is read. `--debug` no longer captures streaming response bodies (`isStreamingResponse` in `diagnostics.go.stmpl`), which previously held every event until the server closed the stream. +An optional `output.stream.metadata` object adds a single advisory stderr line to a projected stream: + +```yaml +output: + stream: + select: $.data.text + metadata: + select: $.data.resource.id + label: Resource ID +``` + +Both metadata fields are required nonempty strings. `select` uses the same singular JSONPath and union-aware string/null schema validation as the text projection. Labels accept printable characters only. The shared projector observes metadata in successfully decoded events, including events without text, and retains only the latest nonempty string. At this projection stage, missing, null, empty, or non-string values do not erase it or fail text rendering. Normal typed SDK schema and decoding errors still apply before projection; a value incompatible with the generated event model can fail the stream and suppress the metadata line. + +After clean completion and successful stdout newline termination, it writes `Resource ID: "value"` once to stderr. Values use Go ASCII string quoting with quotes retained; labels are escaped defensively. Control characters and Unicode cannot inject terminal sequences or additional lines. A text-empty stream can also emit the existing empty-projection notice. Cancellation, stream errors, text projection errors, and stdout write failures suppress the metadata line. Stderr writes are best-effort advisory output. + +The same metadata applies to intent and operation commands, including promoted operations. Explicit output formats, changed `--jq`, and true `--raw-response` bypass projection and metadata. Agent mode and other `IsMachineMode` cases suppress metadata without altering their existing stdout behavior. No metadata configuration preserves existing output. + **Timing proof**: `intentstream_test.go.stmpl` (emitted when the manifest declares an SSE projection whose inputs are satisfiable from one positional) runs a mock SSE server that pauses 300ms between events and, between events, waits until the CLI's stdout writer has observed the previous event (a causal handshake — a batch-at-end implementation deadlocks it and fails, verified by mutation). It asserts one byte-exact `Write` per event, ≥200ms between consecutive event writes, exact concatenation plus one LF, and the explicit `--output-format json` / `--jq` / `--output-format pretty` opt-outs. **Value suggestions and defaults** (`suggestions:` on a declared arg or flag): a declared input's help ends in one parenthetical, `(e.g. , default: )`. Suggestions come from the bound property's schema enum (first four values, then `, ...`) unless the input declares `suggestions:`, a list of unique scalars matching its type that is shown in full and in authored order; `[]` shows none. A command that narrows the value space (a modality-specific model, a pinned engine family) uses it to replace a general-purpose enum, including values the schema enum lacks: suggestions are display-only and never validated, and in route dispatch a declared list also replaces the cross-route intersection. The default is the effective preset when one sets the bound field (that is what the request carries when the flag is omitted), else the declared or `defaultFrom: schema` value; it is removed from the displayed suggestions, including on operation flags where Cobra prints the registered default itself. `--usage` carries a `suggestions` child node on both `flag` and `arg` nodes, and `default=` on `flag` nodes as a separate field. @@ -1044,7 +1061,7 @@ x-speakeasy-cli-commands: summary: Stream events as they arrive ``` -`operations` is a strict map keyed by resolvable `operationId`; each value permits only `output.stream.select` and `flags`. Unknown/duplicate keys, nonexistent operations, non-streaming projections, and flag collisions are generation errors. Operation flags use the same `to`, `type`, `shorthand`, `summary`, `default`, `defaultFrom: schema`, and `suggestions` keys as intent flags, but cannot be `required`, variadic, or bind outside a single top-level body property. For a union request body the property must exist as the same scalar type in every variant. `defaultFrom: schema` requires the same actual default in every variant; the value appears in help while the generated SDK remains responsible for materializing that schema default on the wire. +`operations` is a strict map keyed by resolvable `operationId`; each value permits only `output.stream.select`, `output.stream.metadata`, and `flags`. Unknown/duplicate keys, nonexistent operations, non-streaming projections, and flag collisions are generation errors. Operation flags use the same `to`, `type`, `shorthand`, `summary`, `default`, `defaultFrom: schema`, and `suggestions` keys as intent flags, but cannot be `required`, variadic, or bind outside a single top-level body property. For a union request body the property must exist as the same scalar type in every variant. `defaultFrom: schema` requires the same actual default in every variant; the value appears in help while the generated SDK remains responsible for materializing that schema default on the wire. Operation-declared names are checked against generated parameter/body/security flags, inherited/root flags, `--schema`, `--body`, the operation whole-body flag, pagination (`--all/-a`, `--max-pages`), and binary output (`--output-file`, `--output-b64`). Each registered flag carries `speakeasy:op-declared-input=`. The shared operation run function merges only flags with that annotation on the invoking Cobra command, so an intent that reuses the run function and independently declares `--stream` is unaffected. A changed operation flag merges into `--body`, the union whole-body flag, or stdin and produces the same duplicate-source error if that JSON already contains the key; `@path` and `@-` body values are resolved before this merge for both operation and intent inputs. With no body, flags synthesize a minimal JSON object only when the OpenAPI request body is optional; a required request body keeps its existing CLI-side missing-body error. diff --git a/templates/templates/cli/auxiliary/internal/output/streaming.go.stmpl b/templates/templates/cli/auxiliary/internal/output/streaming.go.stmpl index 6698b1d53..d038c158d 100644 --- a/templates/templates/cli/auxiliary/internal/output/streaming.go.stmpl +++ b/templates/templates/cli/auxiliary/internal/output/streaming.go.stmpl @@ -147,8 +147,12 @@ func StreamResult(cmd *cobra.Command, res interface{}, streamFieldName string) e } if projector != nil { + if err := projector.finish(out); err != nil { + return err + } projector.reportEmpty(cmd) - return projector.finish(out) + projector.reportMetadata(cmd) + return nil } return nil } diff --git a/templates/templates/cli/auxiliary/internal/output/streamproject.go.stmpl b/templates/templates/cli/auxiliary/internal/output/streamproject.go.stmpl index 178df3235..599f49847 100644 --- a/templates/templates/cli/auxiliary/internal/output/streamproject.go.stmpl +++ b/templates/templates/cli/auxiliary/internal/output/streamproject.go.stmpl @@ -17,11 +17,14 @@ import ( const streamSelectAnnotation = "speakeasy_stream_select" type streamProjector struct { - pointer []string - select_ string - events int - wrote bool - lastByte byte + metadataPointer []string + metadataLabel string + metadataValue string + pointer []string + select_ string + events int + wrote bool + lastByte byte } func newStreamProjector(cmd *cobra.Command) *streamProjector { @@ -45,7 +48,10 @@ func newStreamProjector(cmd *cobra.Command) *streamProjector { if rawResponse, _ := flagutil.GetBoolFlag(cmd, "raw-response"); rawResponse { return nil } - return &streamProjector{pointer: splitJSONPointer(pointer), select_: pointer} + return &streamProjector{pointer: splitJSONPointer(pointer), select_: pointer, + metadataPointer: splitJSONPointer(cmd.Annotations["speakeasy_stream_metadata_select"]), + metadataLabel: cmd.Annotations["speakeasy_stream_metadata_label"], + } } func splitJSONPointer(pointer string) []string { @@ -70,6 +76,12 @@ func (p *streamProjector) emit(out io.Writer, item interface{}) error { if err := json.Unmarshal(data, &decoded); err != nil { return fmt.Errorf("stream projection: decode event: %w", err) } + if len(p.metadataPointer) > 0 { + value, _ := walkJSONPointer(decoded, p.metadataPointer) + if text, ok := value.(string); ok && text != "" { + p.metadataValue = text + } + } value, found := walkJSONPointer(decoded, p.pointer) if !found || value == nil { return nil @@ -91,6 +103,14 @@ func (p *streamProjector) finish(out io.Writer) error { return p.write(out, []byte{'\n'}) } +func (p *streamProjector) reportMetadata(cmd *cobra.Command) { + if p == nil || p.metadataValue == "" || p.metadataLabel == "" || IsMachineMode(cmd) || cmd.Context().Err() != nil { + return + } + label := strconv.QuoteToASCII(p.metadataLabel) + fmt.Fprintf(cmd.ErrOrStderr(), "%s: %s\n", label[1:len(label)-1], strconv.QuoteToASCII(p.metadataValue)) +} + func (p *streamProjector) reportEmpty(cmd *cobra.Command) { if p == nil || p.wrote || p.events == 0 || IsMachineMode(cmd) { return diff --git a/templates/templates/cli/includes/intents.ts b/templates/templates/cli/includes/intents.ts index f2cfdb402..566c0604a 100644 --- a/templates/templates/cli/includes/intents.ts +++ b/templates/templates/cli/includes/intents.ts @@ -135,6 +135,8 @@ interface IntentCmdCtx { AsyncMissingStateTestJSON: string; AsyncMissingHandleTestJSON: string; AsyncFailureHint: string; + StreamMetadataPointer: string; + StreamMetadataLabel: string; StreamSelect: string; // RFC 6901 pointer of output.stream.select ("" = none) StreamToggle: { Name: string; Key: string } | null; StreamKind: string; // "sse" | "jsonl" | "" — how the backing operation streams @@ -199,6 +201,8 @@ interface CLIOperationFlagCtx { interface CLIOperationCtx { OperationID: string; + StreamMetadataPointer: string; + StreamMetadataLabel: string; StreamSelect: string; Flags: CLIOperationFlagCtx[]; BodyFlags: string[]; @@ -1332,6 +1336,8 @@ function collectIntentManifest(): IntentManifestCtx { AsyncMissingHandleTestJSON: asyncMissingHandleTestJSON, AsyncFailureHint: cmd.Hints?.CLI_ASYNC_FAILED?.[0] || "", StreamSelect: cmd.Output?.Stream?.Pointer || "", + StreamMetadataPointer: cmd.Output?.Stream?.Metadata?.Pointer || "", + StreamMetadataLabel: cmd.Output?.Stream?.Metadata?.Label || "", StreamToggle: !dispatch && intentStreamKind(found.op).kind ? intentDefaultOnStreamToggle(flags, presetJSON) @@ -1563,6 +1569,8 @@ function getCLIOperationCtx(op: Operation): CLIOperationCtx | null { return { OperationID: declared.OperationID, StreamSelect: declared.Output?.Stream?.Pointer || "", + StreamMetadataPointer: declared.Output?.Stream?.Metadata?.Pointer || "", + StreamMetadataLabel: declared.Output?.Stream?.Metadata?.Label || "", Flags: flags, BodyFlags: bodyFlags, CanonicalBodyFlag: bodyFlags[bodyFlags.length - 1] || "", diff --git a/templates/templates/cli/intentcmd.go.stmpl b/templates/templates/cli/intentcmd.go.stmpl index 32d42277f..f71cf4803 100644 --- a/templates/templates/cli/intentcmd.go.stmpl +++ b/templates/templates/cli/intentcmd.go.stmpl @@ -73,6 +73,10 @@ func InitIntent{{$c.FuncName}}(parent *cobra.Command) error { {{- end}} {{- if $c.StreamSelect}} "speakeasy_stream_select": "{{escapeGoString $c.StreamSelect}}", + {{- if $c.StreamMetadataPointer}} + "speakeasy_stream_metadata_select": "{{escapeGoString $c.StreamMetadataPointer}}", + "speakeasy_stream_metadata_label": "{{escapeGoString $c.StreamMetadataLabel}}", + {{- end}} {{- end}} }, } diff --git a/templates/templates/cli/opcmd.go.stmpl b/templates/templates/cli/opcmd.go.stmpl index 2cb69cd8f..5f49fe068 100644 --- a/templates/templates/cli/opcmd.go.stmpl +++ b/templates/templates/cli/opcmd.go.stmpl @@ -54,6 +54,10 @@ func {{$initFuncName}}(parent *cobra.Command) error { parent.Annotations["speakeasy_cli_promoted"] = "true" {{- if and $cliOp $cliOp.StreamSelect}} parent.Annotations["speakeasy_stream_select"] = "{{escapeGoString $cliOp.StreamSelect}}" + {{- if $cliOp.StreamMetadataPointer}} + parent.Annotations["speakeasy_stream_metadata_select"] = "{{escapeGoString $cliOp.StreamMetadataPointer}}" + parent.Annotations["speakeasy_stream_metadata_label"] = "{{escapeGoString $cliOp.StreamMetadataLabel}}" + {{- end}} {{- end}} {{- if or $hasSecurity $op.Request (hasPagination $op) (hasBinaryResponse $op) (and $cliOp $cliOp.Flags)}} cmd := parent // register flags on the parent @@ -78,6 +82,10 @@ func {{$initFuncName}}(parent *cobra.Command) error { "speakeasy_operation": "{{escapeGoString $op.OriginalID}}", {{- if and $cliOp $cliOp.StreamSelect}} "speakeasy_stream_select": "{{escapeGoString $cliOp.StreamSelect}}", + {{- if $cliOp.StreamMetadataPointer}} + "speakeasy_stream_metadata_select": "{{escapeGoString $cliOp.StreamMetadataPointer}}", + "speakeasy_stream_metadata_label": "{{escapeGoString $cliOp.StreamMetadataLabel}}", + {{- end}} {{- end}} }, } diff --git a/templates/templates/cli/tests/primary/streammetadata_additional_test.go.stmpl b/templates/templates/cli/tests/primary/streammetadata_additional_test.go.stmpl new file mode 100644 index 000000000..7cc2c846c --- /dev/null +++ b/templates/templates/cli/tests/primary/streammetadata_additional_test.go.stmpl @@ -0,0 +1,309 @@ +package tests + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "net/http/httptest" + "strconv" + "strings" + "testing" + + "github.com/spf13/cobra" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "{{getGolangPackage}}/internal/cli" + "{{getGolangPackage}}/internal/config" + "{{getGolangPackage}}/internal/output" +) + +func TestStreamMetadataGeneratedCommands(t *testing.T) { + for _, command := range [][]string{ + {"generate", "hello"}, + {"stream-reply", "hello"}, + {"stream-reply", "hello", "--agent", "worker"}, + {"stream-metadata", "stream-metadata"}, + {"request-bodies", "cli-interact", "--body", `{"model":"model-a","input":"hello"}`, "--stream=true"}, + } { + t.Run(strings.Join(command[:1], " "), func(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/event-stream") + fmt.Fprint(w, "data: {\"resource_id\":\"first\"}\n\ndata: {\"content\":\"Hello\"}\n\ndata: {\"resource_id\":\"last\"}\n\ndata: [DONE]\n\n") + })) + defer srv.Close() + for _, mode := range []struct { + name string + args []string + }{ + {"default", nil}, + {"json", []string{"--output-format", "json"}}, + {"pretty", []string{"--output-format", "pretty"}}, + {"jq", []string{"--jq", ".", "--stream=true"}}, + {"agent", []string{"--agent-mode"}}, + } { + t.Run(mode.name, func(t *testing.T) { + t.Cleanup(config.ResetKeyring) + h := NewCLITestHarness(t) + h.resetAndSetupEnv() + root, err := cli.NewRootCommand() + require.NoError(t, err) + root.SetOut(h.stdout) + root.SetErr(h.stderr) + root.SetIn(strings.NewReader("")) + args := append([]string{"--server-url", srv.URL, "--color", "never", "--no-interactive", "--no-keyring"}, command...) + args = append(args, mode.args...) + require.NoError(t, cli.ExecuteRoot(context.Background(), root, args), h.GetStderr()) + switch mode.name { + case "default", "agent": + assert.Equal(t, "Hello\n", h.GetStdout()) + case "json", "jq": + assertMetadataJSONEvents(t, h.GetStdout(), + `{"data":{"resource_id":"first"}}`, + `{"data":{"content":"Hello"}}`, + `{"data":{"resource_id":"last"}}`, + ) + case "pretty": + assert.Equal(t, 3, strings.Count(h.GetStdout(), "data:")) + assert.Regexp(t, `resource_id:\s+first\b`, h.GetStdout()) + assert.Regexp(t, `content:\s+Hello\b`, h.GetStdout()) + assert.Regexp(t, `resource_id:\s+last\b`, h.GetStdout()) + } + if mode.name == "default" { + assert.Equal(t, "Resource ID: \"last\"\n", h.GetStderr()) + } else { + assert.Empty(t, h.GetStderr()) + } + }) + } + }) + } +} + +func assertMetadataJSONEvents(t *testing.T, stdout string, want ...string) { + t.Helper() + decoder := json.NewDecoder(strings.NewReader(stdout)) + for _, event := range want { + var got json.RawMessage + require.NoError(t, decoder.Decode(&got)) + assert.JSONEq(t, event, string(got)) + } + var extra json.RawMessage + require.ErrorIs(t, decoder.Decode(&extra), io.EOF) +} + +func TestStreamMetadataGeneratedCommandDecodeFailure(t *testing.T) { + t.Cleanup(config.ResetKeyring) + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/event-stream") + fmt.Fprint(w, "data: {\"resource_id\":\"valid\",\"content\":\"Hello\"}\n\ndata: {\"resource_id\":12}\n\ndata: [DONE]\n\n") + })) + defer srv.Close() + h := NewCLITestHarness(t) + h.resetAndSetupEnv() + root, err := cli.NewRootCommand() + require.NoError(t, err) + root.SetOut(h.stdout) + root.SetErr(h.stderr) + root.SetIn(strings.NewReader("")) + err = cli.ExecuteRoot(context.Background(), root, []string{ + "--server-url", srv.URL, "--color", "never", "--no-interactive", "--no-keyring", "--agent-mode=false", + "stream-metadata", "stream-metadata", + }) + var decodeErr *json.UnmarshalTypeError + require.ErrorAs(t, err, &decodeErr) + assert.Equal(t, "number", decodeErr.Value) + assert.Equal(t, "string", decodeErr.Type.String()) + classification, ok := output.ClassificationFrom(err) + require.True(t, ok) + assert.Equal(t, output.ErrorTypeProtocol, classification.Type) + assert.Equal(t, output.ReasonCLIProtocol, classification.Reason) + assert.Equal(t, "Hello\n", h.GetStdout()) + assert.Contains(t, h.GetStderr(), "CLI_PROTOCOL") + assert.NotContains(t, h.GetStderr(), "Resource ID:") +} + +type metadataTestStream struct { + items []map[string]interface{} + index int + err error + cancel context.CancelFunc + cancelAtEnd bool +} + +func (s *metadataTestStream) Next() bool { + if s.index == len(s.items) { + if s.cancelAtEnd && s.cancel != nil { + s.cancel() + } + return false + } + s.index++ + if s.cancel != nil && !s.cancelAtEnd { + s.cancel() + } + return true +} +func (s *metadataTestStream) Value() map[string]interface{} { return s.items[s.index-1] } +func (s *metadataTestStream) Err() error { return s.err } +func (s *metadataTestStream) Close() error { return nil } + +type metadataFailWriter struct{ finishOnly bool } + +func (w metadataFailWriter) Write(p []byte) (int, error) { + if !w.finishOnly || string(p) == "\n" { + return 0, io.ErrShortWrite + } + return len(p), nil +} + +func metadataTestCommand(t *testing.T, out io.Writer, stderr io.Writer) *cobra.Command { + t.Helper() + h := NewCLITestHarness(t) + h.resetAndSetupEnv() + cmd := &cobra.Command{Annotations: map[string]string{ + "speakeasy_stream_select": "/text", + "speakeasy_stream_metadata_select": "/id", + "speakeasy_stream_metadata_label": "Resource ID", + }} + cmd.SetContext(context.Background()) + cmd.SetOut(out) + cmd.SetErr(stderr) + cmd.Flags().String("output-format", "pretty", "") + cmd.Flags().String("jq", "", "") + cmd.Flags().Bool("raw-response", false, "") + cmd.Flags().String("color", "never", "") + return cmd +} + +func TestStreamMetadataRetention(t *testing.T) { + for _, tc := range []struct { + name string + values []interface{} + want string + }{ + {"absent", nil, ""}, + {"first", []interface{}{"first"}, "first"}, + {"repeated", []interface{}{"same", "same"}, "same"}, + {"latest", []interface{}{"first", "last"}, "last"}, + {"invalid after valid", []interface{}{"keep", nil, "", 12, map[string]interface{}{"id": "nested"}}, "keep"}, + {"escaping", []interface{}{"line\n\r\x1b[31m\u202e\u2028雪\"\\"}, "line\n\r\x1b[31m\u202e\u2028雪\"\\"}, + } { + for _, text := range []bool{false, true} { + t.Run(fmt.Sprintf("%s/text=%t", tc.name, text), func(t *testing.T) { + var stdout, stderr bytes.Buffer + cmd := metadataTestCommand(t, &stdout, &stderr) + stream := &metadataTestStream{} + for _, v := range tc.values { + stream.items = append(stream.items, map[string]interface{}{"id": v}) + } + if text { + stream.items = append(stream.items, map[string]interface{}{"text": "hello"}) + } + require.NoError(t, output.StreamResult(cmd, struct{ Stream *metadataTestStream }{stream}, "Stream")) + if text { + assert.Equal(t, "hello\n", stdout.String()) + } else { + assert.Empty(t, stdout.String()) + } + if tc.want == "" { + assert.NotContains(t, stderr.String(), "Resource ID:") + } else { + assert.Equal(t, 1, strings.Count(stderr.String(), "Resource ID:")) + assert.Contains(t, stderr.String(), "Resource ID: "+strconv.QuoteToASCII(tc.want)+"\n") + } + }) + } + } +} + +func TestStreamMetadataSuppressesOnFailure(t *testing.T) { + for _, failure := range []string{"stream", "cancel", "text type", "write", "finish"} { + t.Run(failure, func(t *testing.T) { + var stdout, stderr bytes.Buffer + cmd := metadataTestCommand(t, &stdout, &stderr) + stream := &metadataTestStream{items: []map[string]interface{}{map[string]interface{}{"id": "valid", "text": "hello"}}} + switch failure { + case "stream": + stream.err = errors.New("stream interrupted") + case "cancel": + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + cmd.SetContext(ctx) + stream.cancel = cancel + case "text type": + stream.items[0]["text"] = 17 + case "write": + cmd.SetOut(metadataFailWriter{}) + case "finish": + cmd.SetOut(metadataFailWriter{finishOnly: true}) + } + require.Error(t, output.StreamResult(cmd, struct{ Stream *metadataTestStream }{stream}, "Stream")) + assert.NotContains(t, stderr.String(), "Resource ID:") + }) + } +} + +func TestStreamMetadataProjectionBypass(t *testing.T) { + for _, flag := range []string{"output-format", "jq", "raw-response"} { + t.Run(flag, func(t *testing.T) { + var stdout, stderr bytes.Buffer + cmd := metadataTestCommand(t, &stdout, &stderr) + value := map[string]string{"output-format": "json", "jq": ".", "raw-response": "true"}[flag] + require.NoError(t, cmd.Flags().Set(flag, value)) + stream := &metadataTestStream{items: []map[string]interface{}{map[string]interface{}{"id": "valid", "text": "hello"}}} + require.NoError(t, output.StreamResult(cmd, struct{ Stream *metadataTestStream }{stream}, "Stream")) + if flag == "raw-response" { + assert.Equal(t, "id: valid\ntext: hello\n", stdout.String()) + } else { + assertMetadataJSONEvents(t, stdout.String(), `{"id":"valid","text":"hello"}`) + } + assert.Empty(t, stderr.String()) + }) + } +} + +func TestStreamMetadataConfiguredMachineOutput(t *testing.T) { + var stdout, stderr bytes.Buffer + cmd := metadataTestCommand(t, &stdout, &stderr) + t.Setenv("METADATA_TEST_OUTPUT_FORMAT", "json") + require.NoError(t, config.Init("metadata-test", "METADATA_TEST")) + stream := &metadataTestStream{items: []map[string]interface{}{map[string]interface{}{"id": "valid", "text": "hello"}}} + require.NoError(t, output.StreamResult(cmd, struct{ Stream *metadataTestStream }{stream}, "Stream")) + assertMetadataJSONEvents(t, stdout.String(), `{"id":"valid","text":"hello"}`) + assert.Empty(t, stderr.String()) +} + +func TestStreamMetadataLateCancellationPreservesReturn(t *testing.T) { + for _, mode := range []string{"metadata", "plain projection", "json", "raw"} { + t.Run(mode, func(t *testing.T) { + var stdout, stderr bytes.Buffer + cmd := metadataTestCommand(t, &stdout, &stderr) + switch mode { + case "plain projection": + delete(cmd.Annotations, "speakeasy_stream_metadata_select") + case "json": + require.NoError(t, cmd.Flags().Set("output-format", "json")) + case "raw": + require.NoError(t, cmd.Flags().Set("raw-response", "true")) + } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + cmd.SetContext(ctx) + stream := &metadataTestStream{items: []map[string]interface{}{map[string]interface{}{"id": "valid", "text": "hello"}}, cancel: cancel, cancelAtEnd: true} + require.NoError(t, output.StreamResult(cmd, struct{ Stream *metadataTestStream }{stream}, "Stream")) + require.ErrorIs(t, ctx.Err(), context.Canceled) + assert.NotContains(t, stderr.String(), "Resource ID:") + if mode == "metadata" || mode == "plain projection" { + assert.Equal(t, "hello\n", stdout.String()) + } else if mode == "raw" { + assert.Equal(t, "id: valid\ntext: hello\n", stdout.String()) + } else { + assertMetadataJSONEvents(t, stdout.String(), `{"id":"valid","text":"hello"}`) + } + }) + } +} diff --git a/templates/templates/common/common/typeDefs.d.ts b/templates/templates/common/common/typeDefs.d.ts index a9f853dd9..63f4d8287 100644 --- a/templates/templates/common/common/typeDefs.d.ts +++ b/templates/templates/common/common/typeDefs.d.ts @@ -2324,7 +2324,14 @@ declare global { ResponseCode: string; }; + type CLICommandStreamMetadata = { + Select: string; + Pointer: string; + Label: string; + }; + type CLICommandStreamProjection = { + Metadata?: CLICommandStreamMetadata | null; Select: string; Pointer: string; }; diff --git a/tests/overlays/primary/cli/overlay.yaml b/tests/overlays/primary/cli/overlay.yaml index e776dbeda..fe3656b39 100644 --- a/tests/overlays/primary/cli/overlay.yaml +++ b/tests/overlays/primary/cli/overlay.yaml @@ -88,10 +88,20 @@ actions: categories: - Create operations: + streamMetadata: + output: + stream: + select: $.data.content + metadata: + select: $.data.resource_id + label: Resource ID cliInteract: output: stream: select: $.data.content + metadata: + select: $.data.resource_id + label: Resource ID flags: stream: to: $.stream @@ -149,10 +159,36 @@ actions: output: stream: select: $.data.content + metadata: + select: $.data.resource_id + label: Resource ID examples: basic: summary: Generate with the default model command: cli generate "Explain concurrency in one sentence" + stream-reply: + routes: + model: + op: cliInteract#CliModelInteraction + default: true + selector: model + agent: + op: cliInteract#CliAgentInteraction + selector: agent + args: + input: {to: $.input, variadic: true, summary: Prompt text} + flags: + model: {to: $.model, defaultFrom: schema} + agent: {to: $.agent} + stream: {to: $.stream, type: bool, defaultFrom: schema} + preset: + $.stream: true + output: + stream: + select: $.data.content + metadata: + select: $.data.resource_id + label: Resource ID render: category: Create summary: Run the render model @@ -398,3 +434,36 @@ actions: properties: content: type: string + resource_id: + type: string + +- target: $.paths + update: + /stream-metadata: + get: + operationId: streamMetadata + tags: [streamMetadata] + description: Streamed events can contain text and an optional resource identifier in separate events. + parameters: + - name: stream + in: query + schema: + type: boolean + default: true + responses: + "200": + description: Streamed resource events. + content: + text/event-stream: + x-speakeasy-sse-sentinel: "[DONE]" + schema: + type: object + required: [data] + properties: + data: + type: object + properties: + content: + type: string + resource_id: + type: string diff --git a/tests/overlays/review/cli/overlay.yaml b/tests/overlays/review/cli/overlay.yaml new file mode 100644 index 000000000..7ecac3f72 --- /dev/null +++ b/tests/overlays/review/cli/overlay.yaml @@ -0,0 +1,52 @@ +overlay: 1.0.0 +info: + title: CLI review stream metadata fixture + version: 0.0.0 +actions: + - target: $.paths + update: + /stream-metadata: + get: + operationId: streamMetadata + tags: [streamMetadata] + description: Streamed events can contain text and an optional resource identifier in separate events. + responses: + "200": + description: Streamed resource events. + content: + text/event-stream: + x-speakeasy-sse-sentinel: "[DONE]" + schema: + type: object + required: [data] + properties: + data: + type: object + properties: + content: + type: string + resource_id: + type: string + - target: $['x-speakeasy-cli-commands'].operations + update: + streamMetadata: + output: + stream: + select: $.data.content + metadata: + select: $.data.resource_id + label: Resource ID + - target: $['x-speakeasy-cli-commands'].commands.say.output.stream + update: + metadata: + select: $.data.resource_id + label: Resource ID + - target: $['x-speakeasy-cli-commands'].operations.chat.output.stream + update: + metadata: + select: $.data.resource_id + label: Resource ID + - target: $.paths['/chat'].post.responses['200'].content['text/event-stream'].schema.properties.data.properties + update: + resource_id: + type: string diff --git a/zSDKs/sdk-cli/.speakeasy/gen.lock b/zSDKs/sdk-cli/.speakeasy/gen.lock index 26b1e8d49..c9ae92e48 100644 --- a/zSDKs/sdk-cli/.speakeasy/gen.lock +++ b/zSDKs/sdk-cli/.speakeasy/gen.lock @@ -1,7 +1,7 @@ lockVersion: 2.0.0 id: review-sdk-test-id management: - docChecksum: dd982b4f4b37f4155da107717836388f + docChecksum: b76f0639e425901fecb124d1ffa0f638 docVersion: 0.1.0 speakeasyVersion: internal generationVersion: internal @@ -64,7 +64,7 @@ trackedFiles: internal/cli/binaryandstringupload.go: last_write_checksum: sha1:20d8028b7618e73dcf1763372f9145ea325b32b0 internal/cli/chat.go: - last_write_checksum: sha1:11730e18c9c6f403253ba394cb00e5b6e8beec59 + last_write_checksum: sha1:79b4228fea48fee311f437e253ec4bed6903675e internal/cli/configure.go: last_write_checksum: sha1:72b513337b8bdbb36773683424a76635e6b6a631 internal/cli/createuser.go: @@ -126,7 +126,7 @@ trackedFiles: internal/cli/intent_render.go: last_write_checksum: sha1:9b211c0615b4df7cad91ca9434669eebcc7282e3 internal/cli/intent_say.go: - last_write_checksum: sha1:e11155fa56f0d704c70ee884ad5f5d60a8b8ad1a + last_write_checksum: sha1:d011e10388cdc045a10345e805fc85203f7b426d internal/cli/intents.go: last_write_checksum: sha1:997b951af6d215576d30574a54022937beedd890 internal/cli/intents_order_test.go: @@ -182,7 +182,11 @@ trackedFiles: internal/cli/renderasset.go: last_write_checksum: sha1:c72bde224ebd3246cce2e14e5f04b1e3ed854ba2 internal/cli/root.go: - last_write_checksum: sha1:dad2cd122f67c8465ec46ab90e7e74f9b1f0ce3d + last_write_checksum: sha1:a261d5b828df41f0eef38a293233b9804787fc43 + internal/cli/streammetadata/root.go: + last_write_checksum: sha1:42a01737002d2daef8a33be267f7060659fdac65 + internal/cli/streammetadata/streammetadata.go: + last_write_checksum: sha1:04543b348e7a6cd0f70265220e797c905dd10644 internal/cli/tag1/auth.go: last_write_checksum: sha1:bff8e227f6c34de46d8e5540e23cf616aa5e13a7 internal/cli/tag1/deprecated1.go: @@ -288,9 +292,9 @@ trackedFiles: internal/output/progress.go: last_write_checksum: sha1:f8b839f9394602fe9c30feb3d7155af6235663be internal/output/streaming.go: - last_write_checksum: sha1:daa755592100f096b8056f1018e8b48fae40612d + last_write_checksum: sha1:838823dddf69133729070cc5990fe12d7d69a17e internal/output/streamproject.go: - last_write_checksum: sha1:774db357deee4aefc20c5a46b99193a53d20799e + last_write_checksum: sha1:95088b4a0809c2f02782c950edfe240b8c3e885a internal/sdk/.gitattributes: last_write_checksum: sha1:84b0115789fc3ea52e31df701d8a27f76077e29f internal/sdk/conflicts.go: @@ -432,7 +436,7 @@ trackedFiles: internal/sdk/models/operations/binaryandstringupload.go: last_write_checksum: sha1:7fb4d81daaf907f9894a74cbcda0474399461414 internal/sdk/models/operations/chat.go: - last_write_checksum: sha1:6cb2956ee86eb5a2eed4c4cc621849837a3cd2d2 + last_write_checksum: sha1:aa4756ca1e28c2fbefbbf10e588652e842e67e0d internal/sdk/models/operations/createnamespaceconflict.go: last_write_checksum: sha1:fa39c1f2ddb12ccafded76afcf4cd754aa6b4d21 internal/sdk/models/operations/createsinglenamespacefoopet.go: @@ -515,6 +519,8 @@ trackedFiles: last_write_checksum: sha1:5d8733af5efea2dc50866d5d701a8318ef376605 internal/sdk/models/operations/rootgroupop.go: last_write_checksum: sha1:b5dc1bb6e790596c63264f1aee1b3cd3f38c5658 + internal/sdk/models/operations/streammetadata.go: + last_write_checksum: sha1:6dfbf81ec8b1d0789ab895f43ac9c058a3a8392d internal/sdk/models/operations/subgroupop.go: last_write_checksum: sha1:c1a79613114544955b5452be2dbe8a917e4cfa2e internal/sdk/models/operations/testendpoint.go: @@ -570,7 +576,7 @@ trackedFiles: internal/sdk/retry/config.go: last_write_checksum: sha1:102d1953fbd7e9f312c4442c71ccca2eaaeaa27d internal/sdk/sdk.go: - last_write_checksum: sha1:ed44058323819e0897a4013b1c5df7d11d3a1e1e + last_write_checksum: sha1:9b251ccf79168121a2aff8442bb775a3467bcd74 internal/sdk/sdkinternal/config/sdkconfiguration.go: last_write_checksum: sha1:1e813226ebfcdfdb00c61fa53bb00d34edce6431 internal/sdk/sdkinternal/globals/globals.go: @@ -615,6 +621,8 @@ trackedFiles: last_write_checksum: sha1:d4b8af8f85326ebce36bf0d6039dae458538f822 internal/sdk/singlefoo.go: last_write_checksum: sha1:09e23b19cea18ff983ec83c84ead0f40240bcb88 + internal/sdk/streammetadata.go: + last_write_checksum: sha1:9b1d246eef77f34a0d38be3bd45e156518ae3695 internal/sdk/subgroup.go: last_write_checksum: sha1:f78c5c64805523599cb256fefb3cb3f73b27b2ea internal/sdk/tag1.go: @@ -650,7 +658,7 @@ trackedFiles: internal/usage/bodyschemas.go: last_write_checksum: sha1:775249b69ed405ad072c16a76fe6113f375b3818 internal/usage/schema.go: - last_write_checksum: sha1:1320ae9b96590ef597a1423e64da8993a90925fc + last_write_checksum: sha1:110540be88fd0b33f29d767b732c1c6f4b115d24 scripts/install.ps1: last_write_checksum: sha1:9dcf40ea00ecb8ceda83d5056f57235b43cf658a scripts/install.sh: @@ -922,7 +930,7 @@ trackedFiles: tests/mockserver/internal/sdk/models/operations/binaryandstringupload.go: last_write_checksum: sha1:abbd174263b69f5b19baaec3685c1cfd4375aea6 tests/mockserver/internal/sdk/models/operations/chat.go: - last_write_checksum: sha1:760b8c08c260359b12687db102ad6d4dafbf9413 + last_write_checksum: sha1:d51dfc8a83c2049c9573f1336a4c420888065383 tests/mockserver/internal/sdk/models/operations/createnamespaceconflict.go: last_write_checksum: sha1:c78a9d0dbb60e9e2e14aeb9d8d9ac5a6faf3c001 tests/mockserver/internal/sdk/models/operations/createsinglenamespacefoopet.go: @@ -1003,6 +1011,8 @@ trackedFiles: last_write_checksum: sha1:fdfd8b7d8c8d68be9347be9427d98df24337c129 tests/mockserver/internal/sdk/models/operations/rootgroupop.go: last_write_checksum: sha1:912e9685ab8e556f4b481a0637b5453f41e776d4 + tests/mockserver/internal/sdk/models/operations/streammetadata.go: + last_write_checksum: sha1:e2b5c2b1202222aaf158b675c4bec611aeab8225 tests/mockserver/internal/sdk/models/operations/subgroupop.go: last_write_checksum: sha1:4bf46599b9f0c1cfa33399c873b64069efa5d966 tests/mockserver/internal/sdk/models/operations/testendpoint.go: @@ -1452,6 +1462,7 @@ examples: parameters: path: id: "default-id" + streamMetadata: {} examplesVersion: 1.0.2 generatedTests: testEndpoint: "2026-02-05T03:14:20+10:00" diff --git a/zSDKs/sdk-cli/.speakeasy/logs/naming.log b/zSDKs/sdk-cli/.speakeasy/logs/naming.log index 09d8fd267..ed43ac982 100644 --- a/zSDKs/sdk-cli/.speakeasy/logs/naming.log +++ b/zSDKs/sdk-cli/.speakeasy/logs/naming.log @@ -91,6 +91,9 @@ DEBUG prepend_op_id: Renamed to "renderAsset_request" DEBUG prepend_op_id: Renamed to "getErrorOnlyExample_ResponseBody" labels: "original_name:ResponseBody operation:getErrorOnlyExample requestResponse:response" registrationID: "scope:operations operation:getErrorOnlyExample requestResponse:response responseStatusCode:200 responseMediaType:application/json originalName:ResponseBody" +DEBUG prepend_op_id: Renamed to "streamMetadata_ResponseBody" + labels: "original_name:ResponseBody operation:streamMetadata requestResponse:response responseMediaType:EventStream" + registrationID: "scope:operations operationTag:streamMetadata operation:streamMetadata requestResponse:response responseStatusCode:200 responseMediaType:text/event-stream originalName:ResponseBody" DEBUG prepend_op_id: Renamed to "paymentCreated_request" labels: "original_name:request operation:paymentCreated operationTag:hooks" registrationID: "scope:webhooks operationTag:hooks operation:paymentCreated requestResponse:request constProperty:PaymentCreated originalName:RequestBody" @@ -180,6 +183,15 @@ DEBUG discriminated: Renamed to "ErrorType2_error" registrationID: "scope:shared refType:Schemas refName:ErrorType2 originalName:error" DEBUG +--- Renaming 2 types with name "data" --- +DEBUG discriminated: Renamed to "chat_data" + labels: "original_name:data operation:chat requestResponse:response responseBody:ResponseBody responseMediaType:EventStream" + registrationID: "scope:operations operation:chat requestResponse:response responseStatusCode:200 responseMediaType:text/event-stream responseBody:responseBody originalName:data" +DEBUG discriminated: Renamed to "streamMetadata_data" + labels: "original_name:data operation:streamMetadata requestResponse:response responseBody:ResponseBody responseMediaType:EventStream" + registrationID: "scope:operations operationTag:streamMetadata operation:streamMetadata requestResponse:response responseStatusCode:200 responseMediaType:text/event-stream responseBody:responseBody originalName:data" +DEBUG + --- Renaming 2 types with name "InternalServerError" --- DEBUG discriminated: Renamed to "getUnionErrors_InternalServerError" labels: "scope:errors operation:getUnionErrors data_type:union responseStatusCode:InternalServerError" @@ -268,6 +280,9 @@ DEBUG prepend_op_id: N/A rename "renderAsset_request" DEBUG prepend_op_id: N/A rename "getErrorOnlyExample_ResponseBody" labels: "original_name:ResponseBody operation:getErrorOnlyExample requestResponse:response" registrationID: "scope:operations operation:getErrorOnlyExample requestResponse:response responseStatusCode:200 responseMediaType:application/json originalName:ResponseBody" +DEBUG prepend_op_id: N/A rename "streamMetadata_ResponseBody" + labels: "original_name:ResponseBody operation:streamMetadata requestResponse:response responseMediaType:EventStream" + registrationID: "scope:operations operationTag:streamMetadata operation:streamMetadata requestResponse:response responseStatusCode:200 responseMediaType:text/event-stream originalName:ResponseBody" DEBUG prepend_op_id: N/A rename "paymentCreated_request" labels: "original_name:request operation:paymentCreated operationTag:hooks" registrationID: "scope:webhooks operationTag:hooks operation:paymentCreated requestResponse:request constProperty:PaymentCreated originalName:RequestBody" @@ -371,6 +386,10 @@ GetNamespaceTypesResponse (HttpMeta: HTTPMetadata, NamespaceTypesTest: Namespace GetNamespaceAnimalResponse (HttpMeta: HTTPMetadata, Animal: Animal) GetNamespaceVehicleResponse (HttpMeta: HTTPMetadata, Vehicle: Vehicle) GetNamespaceOrganizationResponse (HttpMeta: HTTPMetadata, Organization: Organization) +StreamMetadata (SDK empty) +StreamMetadataResponse (HttpMeta: HTTPMetadata, object: event-stream) + StreamMetadataResponseBody (data: class) + StreamMetadataData (content: string, resource_id: string) OperationWithLeadingAndTrailingUnderscoresRequest (qp1: string) OperationWithLeadingAndTrailingUnderscoresResponse (HttpMeta: HTTPMetadata) PostFileRequest (upload: File) @@ -446,7 +465,7 @@ ChatRequest (union) ChatResponse (HttpMeta: HTTPMetadata, object: class, ChatStream: event-stream) ChatResponseBody (data: string) ChatStream (data: class) - Data (content: string) + ChatData (content: string, resource_id: string) GetBinaryDefaultResponseResponse (HttpMeta: HTTPMetadata, bytes: response-stream) TestEnumFormatsRequest (stringArrayFormat: enum, stringMapFormat: enum, stringPartialMapFormat: enum ...) StringArrayFormat (enum: pending_review, approved_final, rejected_permanently ...) diff --git a/zSDKs/sdk-cli/README.md b/zSDKs/sdk-cli/README.md index d5bbf1b88..be9fcbdb3 100644 --- a/zSDKs/sdk-cli/README.md +++ b/zSDKs/sdk-cli/README.md @@ -507,6 +507,7 @@ and \'escaped single quotes\' and \"escaped double quotes\". * [`get-namespace-animal`](docs/cli_namespace-tests_types_get-namespace-animal.md) - Get Namespace Animal (Discriminated Union) * [`get-namespace-vehicle`](docs/cli_namespace-tests_types_get-namespace-vehicle.md) - Get Namespace Vehicle (Non-Discriminated Union) * [`get-namespace-organization`](docs/cli_namespace-tests_types_get-namespace-organization.md) - Get Namespace Organization (Nested Inline Schemas) +* [`stream-metadata`](docs/cli_stream-metadata.md) - Streamed events can contain text and an optional resource identifier in separate events. diff --git a/zSDKs/sdk-cli/docs/cli.md b/zSDKs/sdk-cli/docs/cli.md index 3653563f0..852b4937c 100644 --- a/zSDKs/sdk-cli/docs/cli.md +++ b/zSDKs/sdk-cli/docs/cli.md @@ -102,6 +102,7 @@ and \'escaped single quotes\' and \"escaped double quotes\". * [cli render](cli_render.md) - Render an image asset to a file * [cli render-asset](cli_render-asset.md) - Render Asset * [cli say](cli_say.md) - Stream a chat reply +* [cli stream-metadata](cli_stream-metadata.md) - Operations for stream-metadata * [cli tag1](cli_tag1.md) - The first tag * [cli test-endpoint](cli_test-endpoint.md) - Test Endpoint * [cli test-enum-formats](cli_test-enum-formats.md) - Test x-speakeasy-enums in different formats diff --git a/zSDKs/sdk-cli/docs/cli_stream-metadata.md b/zSDKs/sdk-cli/docs/cli_stream-metadata.md new file mode 100644 index 000000000..be15c02b5 --- /dev/null +++ b/zSDKs/sdk-cli/docs/cli_stream-metadata.md @@ -0,0 +1,83 @@ +## cli stream-metadata + +Operations for stream-metadata + +### Synopsis + +Streamed events can contain text and an optional resource identifier in separate events. + +By default, streamed responses write the string selected by $.data.content raw as it arrives. Use -o json to keep each full streamed event. + +``` +cli stream-metadata [flags] +``` + +### Examples + +``` + cli stream-metadata +``` + +### Options + +``` + -h, --help help for stream-metadata +``` + +### Options inherited from parent commands + +``` + --agent-mode Enable structured errors and default TOON output for AI coding agents. + --app-id string Custom authentication credential + --bearer-auth string HTTP Bearer + --client-id string Client Credentials flow. client identifier + --client-secret string Client Credentials flow. client secret + --color string Control colored output: auto (color when output is a TTY), always, or never. Respects NO_COLOR and FORCE_COLOR env vars. (default "auto") + -d, --debug Log request and response diagnostics to stderr + --deprecated-query-param1 string A deprecated description (env: CLI_DEPRECATED_QUERY_PARAM1) + --deprecated-query-param2 string Global deprecated-query-param2 parameter (env: CLI_DEPRECATED_QUERY_PARAM2) + --dry-run Preview API requests without sending them (no network, no OS keychain). Human preview on stderr; with -o json or --jq, one JSON object per request on stdout. Local mutation commands (auth login, auth logout and configure) make no request: they skip prompts and writes and report a no-op (stderr, or one JSON object on stdout in the machine form) + -H, --header stringArray Set a custom HTTP request header (format: "Key: Value"). Can be specified multiple times. + --host-name string Server template variable: HostName + --include-headers Include HTTP response headers in the output + --interactive Prompt for missing inputs and open guided configure/auth forms (forms fall back to line prompts on stdin off-TTY) + -q, --jq string Filter and transform output using a jq expression (e.g., '.name', '.items[] | .id') + --lone-query-param string Global lone-query-param parameter (env: CLI_LONE_QUERY_PARAM) + --mobile-auth string OAuth2 Password flow, a flow that is too + long to describe in a single line. + --my-api-key string API Key + --no-interactive Disable all interactive features (auto-prompting, explorer auto-launch, TUI forms) + --no-keyring Never read or write the OS keychain; store secrets in the config file instead (env: CLI_NO_KEYRING) + --no-retries Disable automatic retries (default: retries enabled with exponential backoff) + --oauth2 string OAuth2 Authorization + -o, --output-format string Specify the output format. Options: pretty, json, yaml, table, toon. (default "pretty") + --password string HTTP Basic password + --port string Server template variable: PORT + --query-param1 string A long winded, multi-line description (env: CLI_QUERY_PARAM1) + --raw-output Write --jq string results as raw text instead of JSON strings (like jq -r); non-string results stay JSON + --retry-config string Full retry config as JSON. Schema: {"strategy":"backoff","backoff":{"initialInterval":500,"maxInterval":10000,"exponent":1.5,"maxElapsedTime":30000},"retryConnectionErrors":false}. Times are in milliseconds. + --retry-connection-errors Retry on connection errors (EOF, reset, etc.) + --retry-max-elapsed-time string Maximum total time for retries (e.g., 30s, 5m). Default: 30s + --secret string Custom authentication credential + --server string Select a server by index (for indexed servers) or name (for named servers) + --server-url string Override the default server URL + --subdomain string Server template variable: subdomain + --timeout string HTTP request timeout (e.g., 30s, 5m, 100ms) + --token-url string Client Credentials flow. token URL + --usage Print the CLI Usage schema in KDL format + --username string HTTP Basic username + --version-param string Server template variable: version +``` + +### SEE ALSO + +* [cli](cli.md) - SDK Review: A test document for reviewing the SDK. + +### Machine interface + +* `cli stream-metadata --usage` — this command's flags, defaults and env vars as machine-readable KDL +* `cli stream-metadata --dry-run` — preview the request without OS-keychain access or a network call (human preview on stderr) +* `--dry-run --output-format json` (or a caller-explicit `--jq`) writes one preview object per request as NDJSON on stdout; jq is not applied to previews +* `--output-format json` or `--jq ` for machine-readable live output; in agent mode errors are a JSON envelope on stderr + +Exit codes: 0 ok · 1 runtime · 2 usage · 3 authentication/authorization diff --git a/zSDKs/sdk-cli/internal/cli/chat.go b/zSDKs/sdk-cli/internal/cli/chat.go index 1ed19e26b..c055a3130 100644 --- a/zSDKs/sdk-cli/internal/cli/chat.go +++ b/zSDKs/sdk-cli/internal/cli/chat.go @@ -22,8 +22,10 @@ func initChatCmd(parent *cobra.Command) error { Args: cobra.NoArgs, RunE: runChatCmd, Annotations: map[string]string{ - "speakeasy_operation": "chat", - "speakeasy_stream_select": "/data/content", + "speakeasy_operation": "chat", + "speakeasy_stream_select": "/data/content", + "speakeasy_stream_metadata_select": "/data/resource_id", + "speakeasy_stream_metadata_label": "Resource ID", }, } cmd.Flags().String("request", "", "Request body as JSON [required]. Can also be provided via stdin; @path reads a file, @- reads stdin to EOF.") diff --git a/zSDKs/sdk-cli/internal/cli/intent_say.go b/zSDKs/sdk-cli/internal/cli/intent_say.go index 412950b97..a6767e488 100644 --- a/zSDKs/sdk-cli/internal/cli/intent_say.go +++ b/zSDKs/sdk-cli/internal/cli/intent_say.go @@ -23,10 +23,12 @@ func InitIntentSay(parent *cobra.Command) error { Args: cobra.ArbitraryArgs, RunE: runIntentSayCmd, Annotations: map[string]string{ - "speakeasy_operation": "chat", - flagutil.AnnotationWholeBodyFlag: "request", - "speakeasy_strict_body_keys": "true", - "speakeasy_stream_select": "/data/content", + "speakeasy_operation": "chat", + flagutil.AnnotationWholeBodyFlag: "request", + "speakeasy_strict_body_keys": "true", + "speakeasy_stream_select": "/data/content", + "speakeasy_stream_metadata_select": "/data/resource_id", + "speakeasy_stream_metadata_label": "Resource ID", }, } cmd.Flags().String("request", "", "Request body as JSON (advanced; merges with intent inputs, rejecting duplicate keys). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.") diff --git a/zSDKs/sdk-cli/internal/cli/root.go b/zSDKs/sdk-cli/internal/cli/root.go index cc7b66779..de9cf15ae 100644 --- a/zSDKs/sdk-cli/internal/cli/root.go +++ b/zSDKs/sdk-cli/internal/cli/root.go @@ -11,6 +11,7 @@ import ( "openapi/internal/cli/group" "openapi/internal/cli/namespacetests" "openapi/internal/cli/obsolete" + "openapi/internal/cli/streammetadata" "openapi/internal/cli/tag1" "openapi/internal/cli/testgroup" "openapi/internal/clierrors" @@ -89,6 +90,9 @@ func NewRootCommand() (*cobra.Command, error) { if err := namespacetests.InitNamespaceTestsRoot(rootCmd); err != nil { return nil, fmt.Errorf("init namespace-tests: %w", err) } + if err := streammetadata.InitStreamMetadataRoot(rootCmd); err != nil { + return nil, fmt.Errorf("init stream-metadata: %w", err) + } if err := initOperationWithLeadingAndTrailingUnderscoresCmd(rootCmd); err != nil { return nil, fmt.Errorf("init operation-with-leading-and-trailing-underscores: %w", err) } diff --git a/zSDKs/sdk-cli/internal/cli/streammetadata/root.go b/zSDKs/sdk-cli/internal/cli/streammetadata/root.go new file mode 100644 index 000000000..0631f8128 --- /dev/null +++ b/zSDKs/sdk-cli/internal/cli/streammetadata/root.go @@ -0,0 +1,32 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package streammetadata + +import ( + "github.com/spf13/cobra" + "openapi/internal/usage" +) + +func InitStreamMetadataRoot(parent *cobra.Command) error { + var StreamMetadataCmd = &cobra.Command{ + Use: "stream-metadata", + Short: "Operations for stream-metadata", + Long: "Operations for stream-metadata", + Args: cobra.NoArgs, + Annotations: map[string]string{"speakeasy_cli_group": "true"}, + RunE: func(cmd *cobra.Command, args []string) error { + if usage.UsageRequested(cmd) { + return usage.EmitSchema(cmd, cmd.OutOrStdout()) + } + return cmd.Help() + }, + Aliases: []string{"sm"}, + } + + if err := initStreamMetadataCmd(StreamMetadataCmd); err != nil { + return err + } + + parent.AddCommand(StreamMetadataCmd) + return nil +} diff --git a/zSDKs/sdk-cli/internal/cli/streammetadata/streammetadata.go b/zSDKs/sdk-cli/internal/cli/streammetadata/streammetadata.go new file mode 100644 index 000000000..9988a089a --- /dev/null +++ b/zSDKs/sdk-cli/internal/cli/streammetadata/streammetadata.go @@ -0,0 +1,73 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package streammetadata + +import ( + "github.com/spf13/cobra" + "openapi/internal/client" + "openapi/internal/output" + "openapi/internal/sdk" + "openapi/internal/sdk/models/operations" + "openapi/internal/usage" +) + +// initStreamMetadataCmd initializes the stream-metadata command. +func initStreamMetadataCmd(parent *cobra.Command) error { + // Promoted: this operation's RunE is set directly on the parent group command. + parent.RunE = runStreamMetadataCmd + parent.Long = "Streamed events can contain text and an optional resource identifier in separate events.\n\nBy default, streamed responses write the string selected by $.data.content raw as it arrives. Use -o json to keep each full streamed event." + parent.Example = " cli stream-metadata" + if parent.Annotations == nil { + parent.Annotations = map[string]string{} + } + parent.Annotations["speakeasy_operation"] = "streamMetadata" + parent.Annotations["speakeasy_cli_promoted"] = "true" + parent.Annotations["speakeasy_stream_select"] = "/data/content" + parent.Annotations["speakeasy_stream_metadata_select"] = "/data/resource_id" + parent.Annotations["speakeasy_stream_metadata_label"] = "Resource ID" + return nil +} + +// runStreamMetadataCmd executes the stream-metadata command. +func runStreamMetadataCmd(cmd *cobra.Command, args []string) error { + if usage.UsageRequested(cmd) { + return usage.EmitSchema(cmd, cmd.OutOrStdout()) + } + s, err := client.NewClient(cmd) + if err != nil { + return err + } + sdkOpts, err := output.PrepareCallOpts(cmd) + if err != nil { + return err + } + // Dry-run: force skip deserialization so the synthetic empty response + // does not cause parse failures in typed response handling. + if client.IsDryRun(cmd) { + sdkOpts = append(sdkOpts, operations.WithSkipDeserialization()) + } + if err := output.ValidateGlobalServerIndex(cmd, len(sdk.ServerList)); err != nil { + return err + } + if output.WantsRawJSON(cmd) { + sdkOpts = append(sdkOpts, operations.WithSkipDeserialization()) + } + // Streaming response — iterate events and output incrementally. + // Skip streaming iteration in dry-run mode (synthetic response has no stream). + if !client.IsDryRun(cmd) { + res, err := s.StreamMetadata.StreamMetadata(cmd.Context(), sdkOpts...) + if err != nil { + return output.Error(cmd, err) + } + return output.StreamResult(cmd, res, "Object") + } + res, err := s.StreamMetadata.StreamMetadata(cmd.Context(), sdkOpts...) + if err != nil { + return output.Error(cmd, err) + } + + if err := output.Result(cmd, res); err != nil { + return err + } + return nil +} diff --git a/zSDKs/sdk-cli/internal/output/streaming.go b/zSDKs/sdk-cli/internal/output/streaming.go index 9059cf2af..8f01a0db2 100644 --- a/zSDKs/sdk-cli/internal/output/streaming.go +++ b/zSDKs/sdk-cli/internal/output/streaming.go @@ -148,8 +148,12 @@ func StreamResult(cmd *cobra.Command, res interface{}, streamFieldName string) e } if projector != nil { + if err := projector.finish(out); err != nil { + return err + } projector.reportEmpty(cmd) - return projector.finish(out) + projector.reportMetadata(cmd) + return nil } return nil } diff --git a/zSDKs/sdk-cli/internal/output/streamproject.go b/zSDKs/sdk-cli/internal/output/streamproject.go index 4c94a5123..81f60f430 100644 --- a/zSDKs/sdk-cli/internal/output/streamproject.go +++ b/zSDKs/sdk-cli/internal/output/streamproject.go @@ -18,11 +18,14 @@ import ( const streamSelectAnnotation = "speakeasy_stream_select" type streamProjector struct { - pointer []string - select_ string - events int - wrote bool - lastByte byte + metadataPointer []string + metadataLabel string + metadataValue string + pointer []string + select_ string + events int + wrote bool + lastByte byte } func newStreamProjector(cmd *cobra.Command) *streamProjector { @@ -46,7 +49,10 @@ func newStreamProjector(cmd *cobra.Command) *streamProjector { if rawResponse, _ := flagutil.GetBoolFlag(cmd, "raw-response"); rawResponse { return nil } - return &streamProjector{pointer: splitJSONPointer(pointer), select_: pointer} + return &streamProjector{pointer: splitJSONPointer(pointer), select_: pointer, + metadataPointer: splitJSONPointer(cmd.Annotations["speakeasy_stream_metadata_select"]), + metadataLabel: cmd.Annotations["speakeasy_stream_metadata_label"], + } } func splitJSONPointer(pointer string) []string { @@ -71,6 +77,12 @@ func (p *streamProjector) emit(out io.Writer, item interface{}) error { if err := json.Unmarshal(data, &decoded); err != nil { return fmt.Errorf("stream projection: decode event: %w", err) } + if len(p.metadataPointer) > 0 { + value, _ := walkJSONPointer(decoded, p.metadataPointer) + if text, ok := value.(string); ok && text != "" { + p.metadataValue = text + } + } value, found := walkJSONPointer(decoded, p.pointer) if !found || value == nil { return nil @@ -92,6 +104,14 @@ func (p *streamProjector) finish(out io.Writer) error { return p.write(out, []byte{'\n'}) } +func (p *streamProjector) reportMetadata(cmd *cobra.Command) { + if p == nil || p.metadataValue == "" || p.metadataLabel == "" || IsMachineMode(cmd) || cmd.Context().Err() != nil { + return + } + label := strconv.QuoteToASCII(p.metadataLabel) + fmt.Fprintf(cmd.ErrOrStderr(), "%s: %s\n", label[1:len(label)-1], strconv.QuoteToASCII(p.metadataValue)) +} + func (p *streamProjector) reportEmpty(cmd *cobra.Command) { if p == nil || p.wrote || p.events == 0 || IsMachineMode(cmd) { return diff --git a/zSDKs/sdk-cli/internal/sdk/models/operations/chat.go b/zSDKs/sdk-cli/internal/sdk/models/operations/chat.go index e30811242..c55a4ccbf 100644 --- a/zSDKs/sdk-cli/internal/sdk/models/operations/chat.go +++ b/zSDKs/sdk-cli/internal/sdk/models/operations/chat.go @@ -106,25 +106,33 @@ func (u ChatRequest) MarshalJSON() ([]byte, error) { return nil, errors.New("could not marshal union type ChatRequest: all fields are null") } -type Data struct { - Content *string `json:"content,omitzero"` +type ChatData struct { + Content *string `json:"content,omitzero"` + ResourceID *string `json:"resource_id,omitzero"` } -func (d *Data) GetContent() *string { - if d == nil { +func (c *ChatData) GetContent() *string { + if c == nil { + return nil + } + return c.Content +} + +func (c *ChatData) GetResourceID() *string { + if c == nil { return nil } - return d.Content + return c.ResourceID } // ChatStream - A stream containing chat completion tokens type ChatStream struct { - Data Data `json:"data"` + Data ChatData `json:"data"` } -func (c *ChatStream) GetData() Data { +func (c *ChatStream) GetData() ChatData { if c == nil { - return Data{} + return ChatData{} } return c.Data } diff --git a/zSDKs/sdk-cli/internal/sdk/models/operations/streammetadata.go b/zSDKs/sdk-cli/internal/sdk/models/operations/streammetadata.go new file mode 100644 index 000000000..df8423fe5 --- /dev/null +++ b/zSDKs/sdk-cli/internal/sdk/models/operations/streammetadata.go @@ -0,0 +1,63 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package operations + +import ( + "openapi/internal/sdk/models/components" + "openapi/internal/sdk/types/stream" +) + +type StreamMetadataData struct { + Content *string `json:"content,omitzero"` + ResourceID *string `json:"resource_id,omitzero"` +} + +func (s *StreamMetadataData) GetContent() *string { + if s == nil { + return nil + } + return s.Content +} + +func (s *StreamMetadataData) GetResourceID() *string { + if s == nil { + return nil + } + return s.ResourceID +} + +// StreamMetadataResponseBody - Streamed resource events. +type StreamMetadataResponseBody struct { + Data StreamMetadataData `json:"data"` +} + +func (s *StreamMetadataResponseBody) GetData() StreamMetadataData { + if s == nil { + return StreamMetadataData{} + } + return s.Data +} + +func (s StreamMetadataResponseBody) GetEventEncoding(event string) (string, error) { + return "application/json", nil +} + +type StreamMetadataResponse struct { + HTTPMeta components.HTTPMetadata `json:"-"` + // Streamed resource events. + Object *stream.EventStream[StreamMetadataResponseBody] +} + +func (s *StreamMetadataResponse) GetHTTPMeta() components.HTTPMetadata { + if s == nil { + return components.HTTPMetadata{} + } + return s.HTTPMeta +} + +func (s *StreamMetadataResponse) GetObject() *stream.EventStream[StreamMetadataResponseBody] { + if s == nil { + return nil + } + return s.Object +} diff --git a/zSDKs/sdk-cli/internal/sdk/sdk.go b/zSDKs/sdk-cli/internal/sdk/sdk.go index b302c705b..f287eb996 100644 --- a/zSDKs/sdk-cli/internal/sdk/sdk.go +++ b/zSDKs/sdk-cli/internal/sdk/sdk.go @@ -73,6 +73,7 @@ type SDK struct { TestGroup *TestGroup Group *Group NamespaceTests *NamespaceTests + StreamMetadata *StreamMetadata sdkConfiguration config.SDKConfiguration hooks *hooks.Hooks @@ -296,6 +297,7 @@ func New(opts ...SDKOption) *SDK { sdk.TestGroup = newTestGroup(sdk, sdk.sdkConfiguration, sdk.hooks) sdk.Group = newGroup(sdk, sdk.sdkConfiguration, sdk.hooks) sdk.NamespaceTests = newNamespaceTests(sdk, sdk.sdkConfiguration, sdk.hooks) + sdk.StreamMetadata = newStreamMetadata(sdk, sdk.sdkConfiguration, sdk.hooks) return sdk } diff --git a/zSDKs/sdk-cli/internal/sdk/streammetadata.go b/zSDKs/sdk-cli/internal/sdk/streammetadata.go new file mode 100644 index 000000000..8756a3e7c --- /dev/null +++ b/zSDKs/sdk-cli/internal/sdk/streammetadata.go @@ -0,0 +1,180 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package sdk + +import ( + "bytes" + "context" + "fmt" + "net/http" + "net/url" + "openapi/internal/sdk/models/components" + "openapi/internal/sdk/models/operations" + "openapi/internal/sdk/models/sdkerrors" + "openapi/internal/sdk/sdkinternal/config" + "openapi/internal/sdk/sdkinternal/hooks" + "openapi/internal/sdk/sdkinternal/utils" + "openapi/internal/sdk/types/stream" +) + +type StreamMetadata struct { + rootSDK *SDK + sdkConfiguration config.SDKConfiguration + hooks *hooks.Hooks +} + +func newStreamMetadata(rootSDK *SDK, sdkConfig config.SDKConfiguration, hooks *hooks.Hooks) *StreamMetadata { + return &StreamMetadata{ + rootSDK: rootSDK, + sdkConfiguration: sdkConfig, + hooks: hooks, + } +} + +// StreamMetadata - Streamed events can contain text and an optional resource identifier in separate events. +func (s *StreamMetadata) StreamMetadata(ctx context.Context, opts ...operations.Option) (*operations.StreamMetadataResponse, error) { + o := operations.Options{} + supportedOptions := []string{ + operations.SupportedOptionTimeout, + operations.SupportedOptionSkipDeserialization, + } + + for _, opt := range opts { + if err := opt(&o, supportedOptions...); err != nil { + return nil, fmt.Errorf("error applying option: %w", err) + } + } + + var baseURL string + if o.ServerURL == nil { + baseURL = utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) + } else { + baseURL = *o.ServerURL + } + opURL, err := url.JoinPath(baseURL, "/stream-metadata") + if err != nil { + return nil, fmt.Errorf("error generating URL: %w", err) + } + + hookCtx := hooks.HookContext{ + SDK: s.rootSDK, + SDKConfiguration: s.sdkConfiguration, + BaseURL: baseURL, + Context: ctx, + OperationID: "streamMetadata", + OAuth2Scopes: []string{"read"}, + SecuritySource: s.sdkConfiguration.Security, + } + + timeout := o.Timeout + if timeout == nil { + timeout = s.sdkConfiguration.Timeout + } + + var streamCancel context.CancelFunc + + if timeout != nil { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, *timeout) + streamCancel = cancel + defer func() { + if streamCancel != nil { + streamCancel() + } + }() + } + + req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil) + if err != nil { + return nil, fmt.Errorf("error creating request: %w", err) + } + req.Header.Set("Accept", "text/event-stream") + req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent) + + if err := utils.PopulateSecurity(ctx, req, s.sdkConfiguration.Security); err != nil { + return nil, err + } + + for k, v := range o.SetHeaders { + req.Header.Set(k, v) + } + + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + if err != nil { + return nil, err + } + + httpRes, err := s.sdkConfiguration.Client.Do(req) + if err != nil || httpRes == nil { + if err != nil { + err = fmt.Errorf("error sending request: %w", err) + } else { + err = fmt.Errorf("error sending request: no response") + } + + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + return nil, err + } else if utils.MatchStatusCodes([]string{"4XX", "5XX"}, httpRes.StatusCode) { + _httpRes, err := s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) + if err != nil { + return nil, err + } else if _httpRes != nil { + httpRes = _httpRes + } + } else { + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + if err != nil { + return nil, err + } + } + + res := &operations.StreamMetadataResponse{ + HTTPMeta: components.HTTPMetadata{ + Request: req, + Response: httpRes, + }, + } + + switch { + case httpRes.StatusCode == 200: + switch { + case utils.MatchContentType(httpRes.Header.Get("Content-Type"), `text/event-stream`): + out := stream.NewEventStream(ctx, httpRes.Body, func(se []byte) (operations.StreamMetadataResponseBody, error) { + var e operations.StreamMetadataResponseBody + if err := utils.UnmarshalJsonFromResponseBody(bytes.NewBuffer(se), &e, ""); err != nil { + return operations.StreamMetadataResponseBody{}, err + } + return e, nil + }, "[DONE]", stream.WithCancel[operations.StreamMetadataResponseBody](streamCancel)) + streamCancel = nil + res.Object = out + default: + rawBody, err := utils.ConsumeRawBody(httpRes) + if err != nil { + return nil, err + } + return nil, sdkerrors.NewSDKDefaultError(fmt.Sprintf("unknown content-type received: %s", httpRes.Header.Get("Content-Type")), httpRes.StatusCode, string(rawBody), httpRes) + } + case httpRes.StatusCode >= 400 && httpRes.StatusCode < 500: + rawBody, err := utils.ConsumeRawBody(httpRes) + if err != nil { + return nil, err + } + return nil, sdkerrors.NewSDKDefaultError("API error occurred", httpRes.StatusCode, string(rawBody), httpRes) + case httpRes.StatusCode >= 500 && httpRes.StatusCode < 600: + rawBody, err := utils.ConsumeRawBody(httpRes) + if err != nil { + return nil, err + } + return nil, sdkerrors.NewSDKDefaultError("API error occurred", httpRes.StatusCode, string(rawBody), httpRes) + default: + rawBody, err := utils.ConsumeRawBody(httpRes) + if err != nil { + return nil, err + } + return nil, sdkerrors.NewSDKDefaultError("unknown status code returned", httpRes.StatusCode, string(rawBody), httpRes) + } + + return res, nil + +} diff --git a/zSDKs/sdk-cli/internal/usage/schema.go b/zSDKs/sdk-cli/internal/usage/schema.go index d5cbd3b59..4b900ef68 100644 --- a/zSDKs/sdk-cli/internal/usage/schema.go +++ b/zSDKs/sdk-cli/internal/usage/schema.go @@ -13,7 +13,7 @@ import ( ) var usageSchemas = map[string]string{ - "": "name \"cli\"\nbin \"cli\"\nabout \"\"\"\n This document will show case as many of our features as possible in as little operations/models as possible.\n This will then generate a SDK that we can more easily review than the test SDKs based on uber.yaml spec.\n \"\"\"\nversion \"0.0.1\"\nconfig {\n file \"~/.config/cli/config.yaml\"\n}\nflag \"--usage\" help=\"Print the CLI Usage schema in KDL format\" global=#true\nflag \"-v --version\" help=\"Print the CLI version\"\nflag \"-o --output-format \" help=\"Specify the output format. Options: pretty, json, yaml, table, toon.\" global=#true config=\"output_format\" default=\"pretty\"\nflag \"--color \" help=\"Control colored output: auto (color when output is a TTY), always, or never. Respects NO_COLOR and FORCE_COLOR env vars.\" global=#true default=\"auto\"\nflag \"-q --jq \" help=\"Filter and transform output using a jq expression (e.g., '.name', '.items[] | .id')\" global=#true\nflag \"--raw-output\" help=\"Write --jq string results as raw text instead of JSON strings (like jq -r); non-string results stay JSON\" global=#true default=#false\nflag \"--server-url \" help=\"Override the default server URL\" global=#true\nflag \"--server \" help=\"Select a server by index (for indexed servers) or name (for named servers)\" global=#true\nflag \"-H --header \" help=\"Set a custom HTTP request header (format: \\\"Key: Value\\\"). Can be specified multiple times.\" global=#true var=#true\nflag \"--include-headers\" help=\"Include HTTP response headers in the output\" global=#true default=#false\nflag \"--timeout \" help=\"HTTP request timeout (e.g., 30s, 5m, 100ms)\" global=#true config=\"timeout\"\nflag \"--interactive\" help=\"Prompt for missing inputs and open guided configure/auth forms (forms fall back to line prompts on stdin off-TTY)\" global=#true default=#false\nflag \"--no-interactive\" help=\"Disable all interactive features (auto-prompting, explorer auto-launch, TUI forms)\" global=#true default=#false\nflag \"--dry-run\" help=\"Preview API requests without sending them (no network, no OS keychain). Human preview on stderr; with -o json or --jq, one JSON object per request on stdout. Local mutation commands (auth login, auth logout and configure) make no request: they skip prompts and writes and report a no-op (stderr, or one JSON object on stdout in the machine form)\" global=#true default=#false\nflag \"-d --debug\" help=\"Log request and response diagnostics to stderr\" global=#true default=#false\nflag \"--agent-mode\" help=\"Enable structured errors and default TOON output for AI coding agents.\" global=#true default=#false\nflag \"--no-retries\" help=\"Disable automatic retries (default: retries enabled with exponential backoff)\" global=#true config=\"no_retries\" default=#false\nflag \"--retry-max-elapsed-time \" help=\"Maximum total time for retries (e.g., 30s, 5m). Default: 30s\" global=#true config=\"retry_max_elapsed_time\"\nflag \"--retry-connection-errors\" help=\"Retry on connection errors (EOF, reset, etc.)\" global=#true config=\"retry_connection_errors\" default=#false\nflag \"--retry-config \" help=\"Full retry config as JSON. Schema: {\\\"strategy\\\":\\\"backoff\\\",\\\"backoff\\\":{\\\"initialInterval\\\":500,\\\"maxInterval\\\":10000,\\\"exponent\\\":1.5,\\\"maxElapsedTime\\\":30000},\\\"retryConnectionErrors\\\":false}. Times are in milliseconds.\" global=#true config=\"retry_config\"\nflag \"--subdomain \" help=\"Server template variable: subdomain\" global=#true\nflag \"--version-param \" help=\"Server template variable: version\" global=#true\nflag \"--host-name \" help=\"Server template variable: HostName\" global=#true\nflag \"--port \" help=\"Server template variable: PORT\" global=#true\nflag \"--username \" help=\"HTTP Basic username\" global=#true env=\"CLI_USERNAME\" config=\"security.username\"\nflag \"--password \" help=\"HTTP Basic password\" global=#true env=\"CLI_PASSWORD\" config=\"security.password\"\nflag \"--bearer-auth \" help=\"HTTP Bearer\" global=#true env=\"CLI_BEARER_AUTH\" config=\"security.bearer_auth\"\nflag \"--my-api-key \" help=\"API Key\" global=#true env=\"CLI_MY_API_KEY\" config=\"security.my_api_key\"\nflag \"--oauth2 \" help=\"OAuth2 Authorization\" global=#true env=\"CLI_OAUTH2\" config=\"security.oauth2\"\nflag \"--app-id \" help=\"Custom authentication credential\" global=#true env=\"CLI_APP_ID\" config=\"security.app_id\"\nflag \"--secret \" help=\"Custom authentication credential\" global=#true env=\"CLI_SECRET\" config=\"security.secret\"\nflag \"--mobile-auth \" help=\"\"\"\n OAuth2 Password flow, a flow that is too\n long to describe in a single line.\n \"\"\" global=#true env=\"CLI_MOBILE_AUTH\" config=\"security.mobile_auth\"\nflag \"--client-id \" help=\"Client Credentials flow. client identifier\" global=#true env=\"CLI_CLIENT_ID\" config=\"security.client_id\"\nflag \"--client-secret \" help=\"Client Credentials flow. client secret\" global=#true env=\"CLI_CLIENT_SECRET\" config=\"security.client_secret\"\nflag \"--token-url \" help=\"Client Credentials flow. token URL\" global=#true env=\"CLI_TOKEN_URL\" config=\"security.token_url\"\nflag \"--no-keyring\" help=\"Never read or write the OS keychain; store secrets in the config file instead\" global=#true env=\"CLI_NO_KEYRING\" config=\"no_keyring\" default=#false\nflag \"--query-param1 \" help=\"A long winded, multi-line description\" global=#true env=\"CLI_QUERY_PARAM1\" config=\"globals.query_param1\"\nflag \"--deprecated-query-param1 \" help=\"A deprecated description\" global=#true env=\"CLI_DEPRECATED_QUERY_PARAM1\" config=\"globals.deprecated_query_param1\"\nflag \"--deprecated-query-param2 \" help=\"Global deprecated-query-param2 parameter\" global=#true env=\"CLI_DEPRECATED_QUERY_PARAM2\" config=\"globals.deprecated_query_param2\"\nflag \"--lone-query-param \" help=\"Global lone-query-param parameter\" global=#true env=\"CLI_LONE_QUERY_PARAM\" config=\"globals.lone_query_param\"\ncmd \"invite\" help=\"Invite a user by email\" {\n arg \"email\" help=\"Email address to invite\" required=#true var=#true\n flag \"--body \" help=\"Request body as JSON (advanced; merges with intent inputs, rejecting duplicate keys). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n flag \"--given-name \" help=\"First name to record\"\n flag \"--user-gender \" help=\"Gender to record (e.g. male, female, other)\" {\n suggestions \"male\" \"female\" \"other\"\n }\n}\ncmd \"enroll\" help=\"Enroll a user by email\" {\n flag \"--body \" help=\"Request body as JSON (advanced; merges with intent inputs, rejecting duplicate keys). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n flag \"--enrollment-email \" help=\"Email address to enroll\"\n}\ncmd \"render\" help=\"Render an image asset to a file\" {\n arg \"prompt\" help=\"Text prompt to render\" required=#true var=#true\n flag \"--body \" help=\"Request body as JSON (advanced; merges with intent inputs, rejecting duplicate keys). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n flag \"--out \" help=\"Write the image to this file (or into this directory). Default: ./render-{timestamp}-{rand}.{ext}\"\n flag \"--raw-response\" help=\"Print the raw API response instead of writing the image to a file\"\n}\ncmd \"produce\" help=\"Produce an image asset and wait for completion\" {\n arg \"prompt\" help=\"Text prompt to render (create input; omit with --resume)\" var=#true\n flag \"--body \" help=\"Request body as JSON (advanced; merges with intent inputs, rejecting duplicate keys). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n flag \"--out \" help=\"Write the image to this file (or into this directory). Default: ./produce-{timestamp}-{rand}.{ext}\"\n flag \"--raw-response\" help=\"Print the raw API response instead of writing the image to a file\"\n flag \"--resume \" help=\"Resume polling an existing operation by ID instead of creating one\"\n flag \"--async\" help=\"Return the operation handle without waiting for a terminal response\"\n flag \"--poll-interval \" help=\"Override the initial polling interval (positive Go duration, for example 500ms or 2s)\"\n flag \"--poll-timeout \" help=\"Override the overall polling deadline (positive Go duration, at least the effective poll interval)\"\n}\ncmd \"observe\" help=\"Produce an asset and print its terminal status\" {\n arg \"prompt\" help=\"Text prompt to render (create input; omit with --resume)\" var=#true\n flag \"--body \" help=\"Request body as JSON (advanced; merges with intent inputs, rejecting duplicate keys). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n flag \"--resume \" help=\"Resume polling an existing operation by ID instead of creating one\"\n flag \"--async\" help=\"Return the operation handle without waiting for a terminal response\"\n flag \"--poll-interval \" help=\"Override the initial polling interval (positive Go duration, for example 500ms or 2s)\"\n flag \"--poll-timeout \" help=\"Override the overall polling deadline (positive Go duration, at least the effective poll interval)\"\n}\ncmd \"say\" help=\"Stream a chat reply\" {\n arg \"prompt\" help=\"Prompt to send\" required=#true var=#true\n flag \"--request \" help=\"Request body as JSON (advanced; merges with intent inputs, rejecting duplicate keys). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n flag \"--stream\" help=\"Stream events as they arrive (default: true)\" default=#true\n}\ncmd \"archive\" help=\"Archive a user account\"\ncmd \"test-group\" help=\"Operations for test-group\" {\n alias \"tg\"\n cmd \"tag2\" help=\"Operations for tag2\" {\n cmd \"post-test\" help=\"Post Test2\" {\n alias \"pt\"\n flag \"--obj \" help=\"A simple object that uses all our supported primitive types and enums and has optional properties. [required]\"\n flag \"-t --type \" help=\"options: type1, type2\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n flag \"--output-file \" help=\"Save the response body to a file path (recommended for binary/file responses)\"\n flag \"--output-b64\" help=\"Encode binary response as base64 and print to stdout\"\n }\n }\n cmd \"tag3\" help=\"Operations for tag3\" {\n cmd \"post-test\" help=\"Post Test2\" {\n alias \"pt\"\n flag \"--obj \" help=\"A simple object that uses all our supported primitive types and enums and has optional properties. [required]\"\n flag \"-t --type \" help=\"options: type1, type2\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n flag \"--output-file \" help=\"Save the response body to a file path (recommended for binary/file responses)\"\n flag \"--output-b64\" help=\"Encode binary response as base64 and print to stdout\"\n }\n }\n}\ncmd \"hello\" help=\"Hand-written command that survives regeneration\"\ncmd \"auth\" help=\"Manage authentication credentials\" {\n cmd \"login\" help=\"Interactively configure authentication credentials\"\n cmd \"logout\" help=\"Clear all stored authentication credentials\"\n cmd \"whoami\" help=\"Display current authentication and global parameter configuration\"\n}\ncmd \"binary-and-string-upload\" help=\"Binary And String Upload\" {\n alias \"basu\"\n flag \"-b --binary \" help=\"binary data (file: or b64:)\"\n flag \"-s --string \" help=\"string value\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n}\ncmd \"chat\" help=\"Chat\" {\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n flag \"--stream\" help=\"Stream events as they arrive\" default=#true\n flag \"--max-tokens \" help=\"Maximum number of tokens to generate\"\n flag \"--temperature \" help=\"Sampling temperature\"\n}\ncmd \"completion\" help=\"Generate the autocompletion script for the specified shell\" {\n cmd \"bash\" help=\"Generate the autocompletion script for bash\"\n cmd \"fish\" help=\"Generate the autocompletion script for fish\"\n cmd \"powershell\" help=\"Generate the autocompletion script for powershell\"\n cmd \"zsh\" help=\"Generate the autocompletion script for zsh\"\n}\ncmd \"configure\" help=\"Configure authentication, global parameters, and preferences\" {\n flag \"--default-output-format \" help=\"Store the default output format without opening the form. Options: pretty, json, yaml, table, toon. Pass an empty value to clear it.\" {\n suggestions \"pretty\" \"json\" \"yaml\" \"table\" \"toon\"\n }\n}\ncmd \"create-user\" help=\"Create User\" {\n alias \"cu\"\n flag \"-i --id \" help=\"string value\"\n flag \"-e --email \" help=\"[required]\"\n flag \"-f --first-name \" help=\"string value\"\n flag \"-l --last-name \" help=\"string value\"\n flag \"--age \" help=\"number value\"\n flag \"-p --postal-code \" help=\"string value\"\n flag \"-g --gender \" help=\"options: male, female, other\"\n flag \"--associated-ids \" help=\"list of values\" var=#true\n flag \"--metadata \" help=\"JSON object\"\n flag \"--metadata-any \" help=\"A metadata object with additionalProperties true (any type) - should be flattened\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n}\ncmd \"create-with-union\" help=\"Create with discriminated union request body\" {\n alias \"cwu\"\n flag \"--dry-run-param\" help=\"If true, validates without creating\"\n flag \"-n --name \" help=\"Name for the shape [required]\"\n flag \"-s --shape \" help=\"{ \\\"type\\\": string, \\\"radius\\\": number, ... } | { \\\"type\\\": string, \\\"width\\\": number, \\\"height\\\": number, ... }\"\n flag \"--shape.circle \" help=\"Circle variant as JSON\"\n flag \"--shape.circle.radius \" help=\"The radius of the circle [required]\"\n flag \"--shape.circle.color-param \" help=\"Optional color of the circle\"\n flag \"--shape.rectangle \" help=\"Rectangle variant as JSON\"\n flag \"--shape.rectangle.width \" help=\"The width of the rectangle [required]\"\n flag \"--shape.rectangle.height \" help=\"The height of the rectangle [required]\"\n flag \"--shape.rectangle.color-param \" help=\"Optional color of the rectangle\"\n flag \"--description \" help=\"Optional description\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n}\ncmd \"delete-user\" help=\"Delete User\" {\n alias \"du\"\n arg \"id\" help=\"string value (or use --id)\"\n flag \"-i --id \" help=\"string value (or pass it as the [id] argument)\"\n}\ncmd \"explore\" help=\"Interactively browse and run commands\"\ncmd \"get-asset\" help=\"Get Asset\" {\n alias \"ga\"\n flag \"-i --id \" help=\"[required]\"\n flag \"-s --stream\" help=\"boolean flag\" default=#true\n}\ncmd \"get-binary-default-response\" help=\"Get Binary Default Response\" {\n alias \"gbdr\"\n flag \"--output-file \" help=\"Save the response body to a file path (recommended for binary/file responses)\"\n flag \"--output-b64\" help=\"Encode binary response as base64 and print to stdout\"\n}\ncmd \"get-duplicate-export-collision\" help=\"Tests that a spec-defined error type colliding with a built-in SDK error name does not cause TS2308\" {\n alias \"gdec\"\n}\ncmd \"get-empty-object-error\" help=\"Get Empty Object Error\" {\n alias \"geoe\"\n}\ncmd \"get-error-in-union\" help=\"Get Error In Union\" {\n alias \"geiu\"\n}\ncmd \"get-error-only-example\" help=\"Operation with example only on error response\" {\n alias \"geoex\"\n}\ncmd \"get-fully-flattened-request\" help=\"Get Fully Flattened Request\" {\n alias \"gffr\"\n flag \"-l --lang \" help=\"[required]\"\n flag \"-m --max-length \" help=\"integer value\"\n flag \"-n --name \" help=\"[required]\"\n flag \"-e --emoji \" help=\"options: wave, smiley, thumbsup, tada\"\n flag \"-g --gif \" help=\"string value\"\n flag \"-r --reply\" help=\"boolean flag\"\n flag \"-p --private\" help=\"boolean flag\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n}\ncmd \"get-named-primitive-union\" help=\"Test named primitive union options using title and x-speakeasy-name-override\" {\n alias \"gnpu\"\n}\ncmd \"get-nested-integer-string\" help=\"Test nested struct with integer:string tag\" {\n alias \"gnis\"\n}\ncmd \"get-polymorphism\" help=\"Get Polymorphism\" {\n alias \"gp\"\n}\ncmd \"get-positional-default\" help=\"Get an item with a default path identifier\" {\n alias \"gpd\"\n arg \"id\" help=\"string value (or use --id)\"\n flag \"-i --id \" help=\"string value (or pass it as the [id] argument)\" default=\"default-id\"\n}\ncmd \"get-request-body-flattened-away\" help=\"Get Request Body Flattened Away\" {\n alias \"grbfa\"\n}\ncmd \"get-union-errors\" help=\"Get Union Errors\" {\n alias \"gue\"\n flag \"-p --page \" help=\"[required]\"\n flag \"-a --all\" help=\"Automatically paginate and fetch all results (streams NDJSON for JSON output)\"\n flag \"--max-pages \" help=\"Maximum number of pages to fetch when using --all (0 = no limit)\" default=0\n}\ncmd \"get-user\" help=\"Get User\" {\n alias \"gu\"\n arg \"id\" help=\"string value (or use --id)\"\n flag \"-i --id \" help=\"string value (or pass it as the [id] argument)\"\n}\ncmd \"group\" help=\"Operations for group\" {\n cmd \"root-group-op\" help=\"An operation at the group's root level\" {\n alias \"rgo\"\n }\n cmd \"sub\" help=\"Operations for sub-group\" {\n cmd \"empty\" help=\"Operations for empty\" {\n cmd \"tail\" help=\"Operations for tail\" {\n cmd \"nested-group-op\" help=\"An operation at the group's deepest level\" {\n alias \"ngo\"\n }\n }\n }\n cmd \"op\" help=\"An operation at the group's top level\"\n }\n}\ncmd \"help\" help=\"Help about any command\"\ncmd \"login\" help=\"Login\"\ncmd \"namespace-tests\" help=\"Operations for namespace-tests\" {\n alias \"nt\"\n cmd \"conflicts\" help=\"Operations for conflicts\" {\n cmd \"create-namespace\" help=\"Create Namespace Conflict Test\" {\n alias \"cn\"\n flag \"-i --id \" help=\"[required]\"\n flag \"-n --name \" help=\"[required]\"\n flag \"-s --species \" help=\"The species of the pet (e.g., dog, cat) [required]\"\n flag \"-m --models \" help=\"A field name that often collides\"\n flag \"-r --request \" help=\"A field name that often collides\"\n flag \"--operations \" help=\"A field name that often collides\"\n flag \"-e --errors \" help=\"A field name that often collides\"\n flag \"-u --utils \" help=\"A field name that often collides\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n }\n cmd \"get-namespace\" help=\"Get Namespace Conflict Test\" {\n alias \"gn\"\n }\n cmd \"get-pet-owners\" help=\"Get Pet Owners\" {\n alias \"gpo\"\n }\n cmd \"get-triple-namespace\" help=\"Get Triple Namespace Conflict Test\" {\n alias \"gtn\"\n }\n cmd \"put-namespace\" help=\"Put Property Name Conflicts Behind\" {\n alias \"pn\"\n flag \"--direct \" help=\"JSON object\"\n flag \"-n --namespaced \" help=\"JSON object\"\n flag \"--overridden \" help=\"JSON object\"\n flag \"-a --allof \" help=\"JSON object\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n }\n }\n cmd \"single-bar\" help=\"Operations for single-bar\" {\n alias \"sb\"\n cmd \"get-single-namespace-bar-pet\" help=\"Get Single Namespace Bar Pet\" {\n alias \"gsnbp\"\n }\n }\n cmd \"single-foo\" help=\"Operations for single-foo\" {\n alias \"sf\"\n cmd \"create-single-namespace-foo-pet\" help=\"Create Single Namespace Foo Pet\" {\n alias \"csnfp\"\n flag \"-i --id \" help=\"[required]\"\n flag \"-n --name \" help=\"[required]\"\n flag \"-s --species \" help=\"The species of the pet (e.g., dog, cat) [required]\"\n flag \"-m --models \" help=\"A field name that often collides\"\n flag \"-r --request \" help=\"A field name that often collides\"\n flag \"--operations \" help=\"A field name that often collides\"\n flag \"-e --errors \" help=\"A field name that often collides\"\n flag \"-u --utils \" help=\"A field name that often collides\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n }\n cmd \"get-single-namespace-foo-pet\" help=\"Get Single Namespace Foo Pet\" {\n alias \"gsnfp\"\n }\n }\n cmd \"types\" help=\"Operations for types\" {\n cmd \"get-namespace\" help=\"Get Namespace Types Test\" {\n alias \"gn\"\n }\n cmd \"get-namespace-animal\" help=\"Get Namespace Animal (Discriminated Union)\" {\n alias \"gna\"\n }\n cmd \"get-namespace-organization\" help=\"Get Namespace Organization (Nested Inline Schemas)\" {\n alias \"gno\"\n }\n cmd \"get-namespace-vehicle\" help=\"Get Namespace Vehicle (Non-Discriminated Union)\" {\n alias \"gnv\"\n }\n }\n}\ncmd \"obsolete\" help=\"A subSDK in which all operations are deprecated\" {\n cmd \"deprecated1\" help=\"Deprecated Operation\"\n}\ncmd \"operation-with-leading-and-trailing-underscores\" help=\"Operation With Leading And Trailing Underscores\" {\n alias \"owlatu\"\n flag \"--qp1 \" help=\"This parameter will not be filled in with the queryParam1 global because it uses x-speakeasy-name-override which results in a non-matching name. [required]\"\n}\ncmd \"parentheses-in-path-allowed\" help=\"A string with \\\\x7b\\\\x7b double braces \\\\x7d\\\\x7d and { single braces }\\\\nand \\\\\\\\{\\\\\\\\{ escaped curlies \\\\\\\\}\\\\\\\\} and `backticks`.\\\\nand \\\\\\\\`escaped backticks\\\\\\\\` and double slashes\\\\\\\\\\\\\\\\\\\\nand 'single quotes' and \\\\\\\"double quotes\\\\\\\".\\\\nand \\\\\\\\'escaped single quotes\\\\\\\\' and \\\\\\\\\\\\\\\"escaped double quotes\\\\\\\\\\\\\\\".\" {\n alias \"pipa\"\n arg \"id\" help=\"string value (or use --id)\"\n flag \"-i --id \" help=\"string value (or pass it as the [id] argument)\"\n flag \"--field-with-braces-in-description \" help=\"\"\"\n A string with " + string([]byte{'{', '{'}) + " double braces " + string([]byte{'}', '}'}) + " and { single braces }\n and \\\\{\\\\{ escaped curlies \\\\}\\\\} and 'backticks'.\n and \\\\'escaped backticks\\\\' and double slashes\\\\\\\\\n and 'single quotes' and \"double quotes\".\n and \\\\'escaped single quotes\\\\' and \\\\\"escaped double quotes\\\\\".\n \"\"\"\n flag \"--field-with-braces-in-default \" help=\"string value\" default=\"\"\"\n A string with " + string([]byte{'{', '{'}) + " double braces " + string([]byte{'}', '}'}) + " and { single braces }\n and \\\\{\\\\{ escaped curlies \\\\}\\\\} and `backticks`.\n and \\\\`escaped backticks\\\\` and double slashes\\\\\\\\\n and 'single quotes' and \"double quotes\".\n and \\\\'escaped single quotes\\\\' and \\\\\"escaped double quotes\\\\\".\n\n \"\"\"\n flag \"--field-with-braces-in-title \" help=\"string value\"\n flag \"--field-with-braces-in-example \" help=\"string value\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n}\ncmd \"post-file\" help=\"Post File\" {\n alias \"pf\"\n flag \"-u --upload \" help=\"A file\"\n flag \"--output-file \" help=\"Save the response body to a file path (recommended for binary/file responses)\"\n flag \"--output-b64\" help=\"Encode binary response as base64 and print to stdout\"\n}\ncmd \"render-asset\" help=\"Render Asset\" {\n alias \"ra\"\n flag \"-p --prompt \" help=\"[required]\"\n flag \"--output-modalities \" help=\"options: text, image\" var=#true\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n}\ncmd \"tag1\" help=\"The first tag\" {\n cmd \"recent\" help=\"List recent test1 pages via tag1\" {\n flag \"-p --page \" help=\"[required]\"\n flag \"--query-param2 \" help=\"\"\"\n An [enum](https://enum.com) \"query parameter\"\n that is not easily described in a single line.\n\n **Available Values:**\n | Value | Description |\n |-------|-------------|\n | 0 | No data |\n | 1 | Partial |\n | 2 | Complete |\n (options: 0, 1, 2) [required]\n \"\"\"\n flag \"--header-param1 \" help=\"[required]\"\n }\n cmd \"auth\" help=\"\"\"\n This operation aims at testing available OAuth2 scopes collection:\n - only operation with oauth2 authorizationCode security flow\n - belongs to a subSDK\n \"\"\" {\n flag \"--access-token \" help=\"Security credential\"\n }\n cmd \"deprecated1\" help=\"Deprecated Operation\"\n cmd \"list-test1\" help=\"Get Test1\" {\n alias \"lt\"\n arg \"page\" help=\"integer value (or use --page)\"\n flag \"-p --page \" help=\"integer value (or pass it as the [page] argument)\"\n flag \"--query-param2 \" help=\"\"\"\n An [enum](https://enum.com) \"query parameter\"\n that is not easily described in a single line.\n\n **Available Values:**\n | Value | Description |\n |-------|-------------|\n | 0 | No data |\n | 1 | Partial |\n | 2 | Complete |\n (options: 0, 1, 2) [required]\n \"\"\"\n flag \"--header-param1 \" help=\"[required]\"\n flag \"-a --all\" help=\"Automatically paginate and fetch all results (streams NDJSON for JSON output)\"\n flag \"--max-pages \" help=\"Maximum number of pages to fetch when using --all (0 = no limit)\" default=0\n }\n cmd \"post-file-with-encoding\" help=\"Post File With Encoding\" {\n alias \"pfwe\"\n flag \"--file \" help=\"The file to upload (supports CSV, PNG, JPEG, or PDF)\"\n flag \"-a --attachment \" help=\"An optional binary attachment\"\n flag \"--file-name \" help=\"Optional custom file name\"\n flag \"--file-purpose \" help=\"Purpose of the file upload\"\n flag \"-m --metadata \" help=\"JSON metadata about the file\"\n }\n}\ncmd \"test-endpoint\" help=\"Test Endpoint\" {\n alias \"te\"\n arg \"test-name\" help=\"string value (or use --test-name)\"\n flag \"-t --test-name \" help=\"string value (or pass it as the [test-name] argument)\"\n flag \"--test \" help=\"[required]\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n}\ncmd \"test-enum-formats\" help=\"Test x-speakeasy-enums in different formats\" {\n alias \"tef\"\n flag \"--string-array-format \" help=\"String enum with x-speakeasy-enums as array (full coverage) (options: pending_review, approved_final, rejected_permanently, arch_x86, mobile_ios, custom_field) [required]\"\n flag \"--string-map-format \" help=\"String enum with x-speakeasy-enums as map (full coverage) (options: low_priority, medium_priority, high_priority, critical_urgent) [required]\"\n flag \"--string-partial-map-format \" help=\"String enum with x-speakeasy-enums as map (partial coverage) (options: draft_mode, under_review, published_live, archived_old) [required]\"\n flag \"--integer-map-format \" help=\"Integer enum with x-speakeasy-enums as map (full coverage) (options: 100, 200, 300, 400) [required]\"\n flag \"--integer-partial-map-format \" help=\"Integer enum with x-speakeasy-enums as map (partial coverage) (options: 1, 2, 3, 4, 5) [required]\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n}\ncmd \"update-user\" help=\"Update User\" {\n alias \"uu\"\n arg \"id\" help=\"string value (or use --id)\"\n flag \"-i --id \" help=\"string value (or pass it as the [id] argument)\"\n flag \"--user.id \" help=\"[required]\"\n flag \"--user.email \" help=\"[required]\"\n flag \"--user.first-name \" help=\"string value\"\n flag \"--user.last-name \" help=\"string value\"\n flag \"--user.age \" help=\"number value\"\n flag \"--user.postal-code \" help=\"string value\"\n flag \"--user.gender \" help=\"options: male, female, other\"\n flag \"--user.associated-ids \" help=\"list of values\" var=#true\n flag \"--user.metadata \" help=\"JSON object\"\n flag \"--user.metadata-any \" help=\"A metadata object with additionalProperties true (any type) - should be flattened\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n}\ncmd \"url-validation-stress-test\" help=\"Url Validation Stress Test\" {\n alias \"uvst\"\n}\ncmd \"validate\" help=\"Validate\"\ncmd \"version\" help=\"Print the CLI version\"\ncmd \"whoami\" help=\"Display current authentication and global parameter configuration\"\n", + "": "name \"cli\"\nbin \"cli\"\nabout \"\"\"\n This document will show case as many of our features as possible in as little operations/models as possible.\n This will then generate a SDK that we can more easily review than the test SDKs based on uber.yaml spec.\n \"\"\"\nversion \"0.0.1\"\nconfig {\n file \"~/.config/cli/config.yaml\"\n}\nflag \"--usage\" help=\"Print the CLI Usage schema in KDL format\" global=#true\nflag \"-v --version\" help=\"Print the CLI version\"\nflag \"-o --output-format \" help=\"Specify the output format. Options: pretty, json, yaml, table, toon.\" global=#true config=\"output_format\" default=\"pretty\"\nflag \"--color \" help=\"Control colored output: auto (color when output is a TTY), always, or never. Respects NO_COLOR and FORCE_COLOR env vars.\" global=#true default=\"auto\"\nflag \"-q --jq \" help=\"Filter and transform output using a jq expression (e.g., '.name', '.items[] | .id')\" global=#true\nflag \"--raw-output\" help=\"Write --jq string results as raw text instead of JSON strings (like jq -r); non-string results stay JSON\" global=#true default=#false\nflag \"--server-url \" help=\"Override the default server URL\" global=#true\nflag \"--server \" help=\"Select a server by index (for indexed servers) or name (for named servers)\" global=#true\nflag \"-H --header \" help=\"Set a custom HTTP request header (format: \\\"Key: Value\\\"). Can be specified multiple times.\" global=#true var=#true\nflag \"--include-headers\" help=\"Include HTTP response headers in the output\" global=#true default=#false\nflag \"--timeout \" help=\"HTTP request timeout (e.g., 30s, 5m, 100ms)\" global=#true config=\"timeout\"\nflag \"--interactive\" help=\"Prompt for missing inputs and open guided configure/auth forms (forms fall back to line prompts on stdin off-TTY)\" global=#true default=#false\nflag \"--no-interactive\" help=\"Disable all interactive features (auto-prompting, explorer auto-launch, TUI forms)\" global=#true default=#false\nflag \"--dry-run\" help=\"Preview API requests without sending them (no network, no OS keychain). Human preview on stderr; with -o json or --jq, one JSON object per request on stdout. Local mutation commands (auth login, auth logout and configure) make no request: they skip prompts and writes and report a no-op (stderr, or one JSON object on stdout in the machine form)\" global=#true default=#false\nflag \"-d --debug\" help=\"Log request and response diagnostics to stderr\" global=#true default=#false\nflag \"--agent-mode\" help=\"Enable structured errors and default TOON output for AI coding agents.\" global=#true default=#false\nflag \"--no-retries\" help=\"Disable automatic retries (default: retries enabled with exponential backoff)\" global=#true config=\"no_retries\" default=#false\nflag \"--retry-max-elapsed-time \" help=\"Maximum total time for retries (e.g., 30s, 5m). Default: 30s\" global=#true config=\"retry_max_elapsed_time\"\nflag \"--retry-connection-errors\" help=\"Retry on connection errors (EOF, reset, etc.)\" global=#true config=\"retry_connection_errors\" default=#false\nflag \"--retry-config \" help=\"Full retry config as JSON. Schema: {\\\"strategy\\\":\\\"backoff\\\",\\\"backoff\\\":{\\\"initialInterval\\\":500,\\\"maxInterval\\\":10000,\\\"exponent\\\":1.5,\\\"maxElapsedTime\\\":30000},\\\"retryConnectionErrors\\\":false}. Times are in milliseconds.\" global=#true config=\"retry_config\"\nflag \"--subdomain \" help=\"Server template variable: subdomain\" global=#true\nflag \"--version-param \" help=\"Server template variable: version\" global=#true\nflag \"--host-name \" help=\"Server template variable: HostName\" global=#true\nflag \"--port \" help=\"Server template variable: PORT\" global=#true\nflag \"--username \" help=\"HTTP Basic username\" global=#true env=\"CLI_USERNAME\" config=\"security.username\"\nflag \"--password \" help=\"HTTP Basic password\" global=#true env=\"CLI_PASSWORD\" config=\"security.password\"\nflag \"--bearer-auth \" help=\"HTTP Bearer\" global=#true env=\"CLI_BEARER_AUTH\" config=\"security.bearer_auth\"\nflag \"--my-api-key \" help=\"API Key\" global=#true env=\"CLI_MY_API_KEY\" config=\"security.my_api_key\"\nflag \"--oauth2 \" help=\"OAuth2 Authorization\" global=#true env=\"CLI_OAUTH2\" config=\"security.oauth2\"\nflag \"--app-id \" help=\"Custom authentication credential\" global=#true env=\"CLI_APP_ID\" config=\"security.app_id\"\nflag \"--secret \" help=\"Custom authentication credential\" global=#true env=\"CLI_SECRET\" config=\"security.secret\"\nflag \"--mobile-auth \" help=\"\"\"\n OAuth2 Password flow, a flow that is too\n long to describe in a single line.\n \"\"\" global=#true env=\"CLI_MOBILE_AUTH\" config=\"security.mobile_auth\"\nflag \"--client-id \" help=\"Client Credentials flow. client identifier\" global=#true env=\"CLI_CLIENT_ID\" config=\"security.client_id\"\nflag \"--client-secret \" help=\"Client Credentials flow. client secret\" global=#true env=\"CLI_CLIENT_SECRET\" config=\"security.client_secret\"\nflag \"--token-url \" help=\"Client Credentials flow. token URL\" global=#true env=\"CLI_TOKEN_URL\" config=\"security.token_url\"\nflag \"--no-keyring\" help=\"Never read or write the OS keychain; store secrets in the config file instead\" global=#true env=\"CLI_NO_KEYRING\" config=\"no_keyring\" default=#false\nflag \"--query-param1 \" help=\"A long winded, multi-line description\" global=#true env=\"CLI_QUERY_PARAM1\" config=\"globals.query_param1\"\nflag \"--deprecated-query-param1 \" help=\"A deprecated description\" global=#true env=\"CLI_DEPRECATED_QUERY_PARAM1\" config=\"globals.deprecated_query_param1\"\nflag \"--deprecated-query-param2 \" help=\"Global deprecated-query-param2 parameter\" global=#true env=\"CLI_DEPRECATED_QUERY_PARAM2\" config=\"globals.deprecated_query_param2\"\nflag \"--lone-query-param \" help=\"Global lone-query-param parameter\" global=#true env=\"CLI_LONE_QUERY_PARAM\" config=\"globals.lone_query_param\"\ncmd \"invite\" help=\"Invite a user by email\" {\n arg \"email\" help=\"Email address to invite\" required=#true var=#true\n flag \"--body \" help=\"Request body as JSON (advanced; merges with intent inputs, rejecting duplicate keys). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n flag \"--given-name \" help=\"First name to record\"\n flag \"--user-gender \" help=\"Gender to record (e.g. male, female, other)\" {\n suggestions \"male\" \"female\" \"other\"\n }\n}\ncmd \"enroll\" help=\"Enroll a user by email\" {\n flag \"--body \" help=\"Request body as JSON (advanced; merges with intent inputs, rejecting duplicate keys). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n flag \"--enrollment-email \" help=\"Email address to enroll\"\n}\ncmd \"render\" help=\"Render an image asset to a file\" {\n arg \"prompt\" help=\"Text prompt to render\" required=#true var=#true\n flag \"--body \" help=\"Request body as JSON (advanced; merges with intent inputs, rejecting duplicate keys). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n flag \"--out \" help=\"Write the image to this file (or into this directory). Default: ./render-{timestamp}-{rand}.{ext}\"\n flag \"--raw-response\" help=\"Print the raw API response instead of writing the image to a file\"\n}\ncmd \"produce\" help=\"Produce an image asset and wait for completion\" {\n arg \"prompt\" help=\"Text prompt to render (create input; omit with --resume)\" var=#true\n flag \"--body \" help=\"Request body as JSON (advanced; merges with intent inputs, rejecting duplicate keys). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n flag \"--out \" help=\"Write the image to this file (or into this directory). Default: ./produce-{timestamp}-{rand}.{ext}\"\n flag \"--raw-response\" help=\"Print the raw API response instead of writing the image to a file\"\n flag \"--resume \" help=\"Resume polling an existing operation by ID instead of creating one\"\n flag \"--async\" help=\"Return the operation handle without waiting for a terminal response\"\n flag \"--poll-interval \" help=\"Override the initial polling interval (positive Go duration, for example 500ms or 2s)\"\n flag \"--poll-timeout \" help=\"Override the overall polling deadline (positive Go duration, at least the effective poll interval)\"\n}\ncmd \"observe\" help=\"Produce an asset and print its terminal status\" {\n arg \"prompt\" help=\"Text prompt to render (create input; omit with --resume)\" var=#true\n flag \"--body \" help=\"Request body as JSON (advanced; merges with intent inputs, rejecting duplicate keys). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n flag \"--resume \" help=\"Resume polling an existing operation by ID instead of creating one\"\n flag \"--async\" help=\"Return the operation handle without waiting for a terminal response\"\n flag \"--poll-interval \" help=\"Override the initial polling interval (positive Go duration, for example 500ms or 2s)\"\n flag \"--poll-timeout \" help=\"Override the overall polling deadline (positive Go duration, at least the effective poll interval)\"\n}\ncmd \"say\" help=\"Stream a chat reply\" {\n arg \"prompt\" help=\"Prompt to send\" required=#true var=#true\n flag \"--request \" help=\"Request body as JSON (advanced; merges with intent inputs, rejecting duplicate keys). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n flag \"--stream\" help=\"Stream events as they arrive (default: true)\" default=#true\n}\ncmd \"archive\" help=\"Archive a user account\"\ncmd \"test-group\" help=\"Operations for test-group\" {\n alias \"tg\"\n cmd \"tag2\" help=\"Operations for tag2\" {\n cmd \"post-test\" help=\"Post Test2\" {\n alias \"pt\"\n flag \"--obj \" help=\"A simple object that uses all our supported primitive types and enums and has optional properties. [required]\"\n flag \"-t --type \" help=\"options: type1, type2\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n flag \"--output-file \" help=\"Save the response body to a file path (recommended for binary/file responses)\"\n flag \"--output-b64\" help=\"Encode binary response as base64 and print to stdout\"\n }\n }\n cmd \"tag3\" help=\"Operations for tag3\" {\n cmd \"post-test\" help=\"Post Test2\" {\n alias \"pt\"\n flag \"--obj \" help=\"A simple object that uses all our supported primitive types and enums and has optional properties. [required]\"\n flag \"-t --type \" help=\"options: type1, type2\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n flag \"--output-file \" help=\"Save the response body to a file path (recommended for binary/file responses)\"\n flag \"--output-b64\" help=\"Encode binary response as base64 and print to stdout\"\n }\n }\n}\ncmd \"hello\" help=\"Hand-written command that survives regeneration\"\ncmd \"auth\" help=\"Manage authentication credentials\" {\n cmd \"login\" help=\"Interactively configure authentication credentials\"\n cmd \"logout\" help=\"Clear all stored authentication credentials\"\n cmd \"whoami\" help=\"Display current authentication and global parameter configuration\"\n}\ncmd \"binary-and-string-upload\" help=\"Binary And String Upload\" {\n alias \"basu\"\n flag \"-b --binary \" help=\"binary data (file: or b64:)\"\n flag \"-s --string \" help=\"string value\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n}\ncmd \"chat\" help=\"Chat\" {\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n flag \"--stream\" help=\"Stream events as they arrive\" default=#true\n flag \"--max-tokens \" help=\"Maximum number of tokens to generate\"\n flag \"--temperature \" help=\"Sampling temperature\"\n}\ncmd \"completion\" help=\"Generate the autocompletion script for the specified shell\" {\n cmd \"bash\" help=\"Generate the autocompletion script for bash\"\n cmd \"fish\" help=\"Generate the autocompletion script for fish\"\n cmd \"powershell\" help=\"Generate the autocompletion script for powershell\"\n cmd \"zsh\" help=\"Generate the autocompletion script for zsh\"\n}\ncmd \"configure\" help=\"Configure authentication, global parameters, and preferences\" {\n flag \"--default-output-format \" help=\"Store the default output format without opening the form. Options: pretty, json, yaml, table, toon. Pass an empty value to clear it.\" {\n suggestions \"pretty\" \"json\" \"yaml\" \"table\" \"toon\"\n }\n}\ncmd \"create-user\" help=\"Create User\" {\n alias \"cu\"\n flag \"-i --id \" help=\"string value\"\n flag \"-e --email \" help=\"[required]\"\n flag \"-f --first-name \" help=\"string value\"\n flag \"-l --last-name \" help=\"string value\"\n flag \"--age \" help=\"number value\"\n flag \"-p --postal-code \" help=\"string value\"\n flag \"-g --gender \" help=\"options: male, female, other\"\n flag \"--associated-ids \" help=\"list of values\" var=#true\n flag \"--metadata \" help=\"JSON object\"\n flag \"--metadata-any \" help=\"A metadata object with additionalProperties true (any type) - should be flattened\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n}\ncmd \"create-with-union\" help=\"Create with discriminated union request body\" {\n alias \"cwu\"\n flag \"--dry-run-param\" help=\"If true, validates without creating\"\n flag \"-n --name \" help=\"Name for the shape [required]\"\n flag \"-s --shape \" help=\"{ \\\"type\\\": string, \\\"radius\\\": number, ... } | { \\\"type\\\": string, \\\"width\\\": number, \\\"height\\\": number, ... }\"\n flag \"--shape.circle \" help=\"Circle variant as JSON\"\n flag \"--shape.circle.radius \" help=\"The radius of the circle [required]\"\n flag \"--shape.circle.color-param \" help=\"Optional color of the circle\"\n flag \"--shape.rectangle \" help=\"Rectangle variant as JSON\"\n flag \"--shape.rectangle.width \" help=\"The width of the rectangle [required]\"\n flag \"--shape.rectangle.height \" help=\"The height of the rectangle [required]\"\n flag \"--shape.rectangle.color-param \" help=\"Optional color of the rectangle\"\n flag \"--description \" help=\"Optional description\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n}\ncmd \"delete-user\" help=\"Delete User\" {\n alias \"du\"\n arg \"id\" help=\"string value (or use --id)\"\n flag \"-i --id \" help=\"string value (or pass it as the [id] argument)\"\n}\ncmd \"explore\" help=\"Interactively browse and run commands\"\ncmd \"get-asset\" help=\"Get Asset\" {\n alias \"ga\"\n flag \"-i --id \" help=\"[required]\"\n flag \"-s --stream\" help=\"boolean flag\" default=#true\n}\ncmd \"get-binary-default-response\" help=\"Get Binary Default Response\" {\n alias \"gbdr\"\n flag \"--output-file \" help=\"Save the response body to a file path (recommended for binary/file responses)\"\n flag \"--output-b64\" help=\"Encode binary response as base64 and print to stdout\"\n}\ncmd \"get-duplicate-export-collision\" help=\"Tests that a spec-defined error type colliding with a built-in SDK error name does not cause TS2308\" {\n alias \"gdec\"\n}\ncmd \"get-empty-object-error\" help=\"Get Empty Object Error\" {\n alias \"geoe\"\n}\ncmd \"get-error-in-union\" help=\"Get Error In Union\" {\n alias \"geiu\"\n}\ncmd \"get-error-only-example\" help=\"Operation with example only on error response\" {\n alias \"geoex\"\n}\ncmd \"get-fully-flattened-request\" help=\"Get Fully Flattened Request\" {\n alias \"gffr\"\n flag \"-l --lang \" help=\"[required]\"\n flag \"-m --max-length \" help=\"integer value\"\n flag \"-n --name \" help=\"[required]\"\n flag \"-e --emoji \" help=\"options: wave, smiley, thumbsup, tada\"\n flag \"-g --gif \" help=\"string value\"\n flag \"-r --reply\" help=\"boolean flag\"\n flag \"-p --private\" help=\"boolean flag\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n}\ncmd \"get-named-primitive-union\" help=\"Test named primitive union options using title and x-speakeasy-name-override\" {\n alias \"gnpu\"\n}\ncmd \"get-nested-integer-string\" help=\"Test nested struct with integer:string tag\" {\n alias \"gnis\"\n}\ncmd \"get-polymorphism\" help=\"Get Polymorphism\" {\n alias \"gp\"\n}\ncmd \"get-positional-default\" help=\"Get an item with a default path identifier\" {\n alias \"gpd\"\n arg \"id\" help=\"string value (or use --id)\"\n flag \"-i --id \" help=\"string value (or pass it as the [id] argument)\" default=\"default-id\"\n}\ncmd \"get-request-body-flattened-away\" help=\"Get Request Body Flattened Away\" {\n alias \"grbfa\"\n}\ncmd \"get-union-errors\" help=\"Get Union Errors\" {\n alias \"gue\"\n flag \"-p --page \" help=\"[required]\"\n flag \"-a --all\" help=\"Automatically paginate and fetch all results (streams NDJSON for JSON output)\"\n flag \"--max-pages \" help=\"Maximum number of pages to fetch when using --all (0 = no limit)\" default=0\n}\ncmd \"get-user\" help=\"Get User\" {\n alias \"gu\"\n arg \"id\" help=\"string value (or use --id)\"\n flag \"-i --id \" help=\"string value (or pass it as the [id] argument)\"\n}\ncmd \"group\" help=\"Operations for group\" {\n cmd \"root-group-op\" help=\"An operation at the group's root level\" {\n alias \"rgo\"\n }\n cmd \"sub\" help=\"Operations for sub-group\" {\n cmd \"empty\" help=\"Operations for empty\" {\n cmd \"tail\" help=\"Operations for tail\" {\n cmd \"nested-group-op\" help=\"An operation at the group's deepest level\" {\n alias \"ngo\"\n }\n }\n }\n cmd \"op\" help=\"An operation at the group's top level\"\n }\n}\ncmd \"help\" help=\"Help about any command\"\ncmd \"login\" help=\"Login\"\ncmd \"namespace-tests\" help=\"Operations for namespace-tests\" {\n alias \"nt\"\n cmd \"conflicts\" help=\"Operations for conflicts\" {\n cmd \"create-namespace\" help=\"Create Namespace Conflict Test\" {\n alias \"cn\"\n flag \"-i --id \" help=\"[required]\"\n flag \"-n --name \" help=\"[required]\"\n flag \"-s --species \" help=\"The species of the pet (e.g., dog, cat) [required]\"\n flag \"-m --models \" help=\"A field name that often collides\"\n flag \"-r --request \" help=\"A field name that often collides\"\n flag \"--operations \" help=\"A field name that often collides\"\n flag \"-e --errors \" help=\"A field name that often collides\"\n flag \"-u --utils \" help=\"A field name that often collides\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n }\n cmd \"get-namespace\" help=\"Get Namespace Conflict Test\" {\n alias \"gn\"\n }\n cmd \"get-pet-owners\" help=\"Get Pet Owners\" {\n alias \"gpo\"\n }\n cmd \"get-triple-namespace\" help=\"Get Triple Namespace Conflict Test\" {\n alias \"gtn\"\n }\n cmd \"put-namespace\" help=\"Put Property Name Conflicts Behind\" {\n alias \"pn\"\n flag \"--direct \" help=\"JSON object\"\n flag \"-n --namespaced \" help=\"JSON object\"\n flag \"--overridden \" help=\"JSON object\"\n flag \"-a --allof \" help=\"JSON object\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n }\n }\n cmd \"single-bar\" help=\"Operations for single-bar\" {\n alias \"sb\"\n cmd \"get-single-namespace-bar-pet\" help=\"Get Single Namespace Bar Pet\" {\n alias \"gsnbp\"\n }\n }\n cmd \"single-foo\" help=\"Operations for single-foo\" {\n alias \"sf\"\n cmd \"create-single-namespace-foo-pet\" help=\"Create Single Namespace Foo Pet\" {\n alias \"csnfp\"\n flag \"-i --id \" help=\"[required]\"\n flag \"-n --name \" help=\"[required]\"\n flag \"-s --species \" help=\"The species of the pet (e.g., dog, cat) [required]\"\n flag \"-m --models \" help=\"A field name that often collides\"\n flag \"-r --request \" help=\"A field name that often collides\"\n flag \"--operations \" help=\"A field name that often collides\"\n flag \"-e --errors \" help=\"A field name that often collides\"\n flag \"-u --utils \" help=\"A field name that often collides\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n }\n cmd \"get-single-namespace-foo-pet\" help=\"Get Single Namespace Foo Pet\" {\n alias \"gsnfp\"\n }\n }\n cmd \"types\" help=\"Operations for types\" {\n cmd \"get-namespace\" help=\"Get Namespace Types Test\" {\n alias \"gn\"\n }\n cmd \"get-namespace-animal\" help=\"Get Namespace Animal (Discriminated Union)\" {\n alias \"gna\"\n }\n cmd \"get-namespace-organization\" help=\"Get Namespace Organization (Nested Inline Schemas)\" {\n alias \"gno\"\n }\n cmd \"get-namespace-vehicle\" help=\"Get Namespace Vehicle (Non-Discriminated Union)\" {\n alias \"gnv\"\n }\n }\n}\ncmd \"obsolete\" help=\"A subSDK in which all operations are deprecated\" {\n cmd \"deprecated1\" help=\"Deprecated Operation\"\n}\ncmd \"operation-with-leading-and-trailing-underscores\" help=\"Operation With Leading And Trailing Underscores\" {\n alias \"owlatu\"\n flag \"--qp1 \" help=\"This parameter will not be filled in with the queryParam1 global because it uses x-speakeasy-name-override which results in a non-matching name. [required]\"\n}\ncmd \"parentheses-in-path-allowed\" help=\"A string with \\\\x7b\\\\x7b double braces \\\\x7d\\\\x7d and { single braces }\\\\nand \\\\\\\\{\\\\\\\\{ escaped curlies \\\\\\\\}\\\\\\\\} and `backticks`.\\\\nand \\\\\\\\`escaped backticks\\\\\\\\` and double slashes\\\\\\\\\\\\\\\\\\\\nand 'single quotes' and \\\\\\\"double quotes\\\\\\\".\\\\nand \\\\\\\\'escaped single quotes\\\\\\\\' and \\\\\\\\\\\\\\\"escaped double quotes\\\\\\\\\\\\\\\".\" {\n alias \"pipa\"\n arg \"id\" help=\"string value (or use --id)\"\n flag \"-i --id \" help=\"string value (or pass it as the [id] argument)\"\n flag \"--field-with-braces-in-description \" help=\"\"\"\n A string with " + string([]byte{'{', '{'}) + " double braces " + string([]byte{'}', '}'}) + " and { single braces }\n and \\\\{\\\\{ escaped curlies \\\\}\\\\} and 'backticks'.\n and \\\\'escaped backticks\\\\' and double slashes\\\\\\\\\n and 'single quotes' and \"double quotes\".\n and \\\\'escaped single quotes\\\\' and \\\\\"escaped double quotes\\\\\".\n \"\"\"\n flag \"--field-with-braces-in-default \" help=\"string value\" default=\"\"\"\n A string with " + string([]byte{'{', '{'}) + " double braces " + string([]byte{'}', '}'}) + " and { single braces }\n and \\\\{\\\\{ escaped curlies \\\\}\\\\} and `backticks`.\n and \\\\`escaped backticks\\\\` and double slashes\\\\\\\\\n and 'single quotes' and \"double quotes\".\n and \\\\'escaped single quotes\\\\' and \\\\\"escaped double quotes\\\\\".\n\n \"\"\"\n flag \"--field-with-braces-in-title \" help=\"string value\"\n flag \"--field-with-braces-in-example \" help=\"string value\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n}\ncmd \"post-file\" help=\"Post File\" {\n alias \"pf\"\n flag \"-u --upload \" help=\"A file\"\n flag \"--output-file \" help=\"Save the response body to a file path (recommended for binary/file responses)\"\n flag \"--output-b64\" help=\"Encode binary response as base64 and print to stdout\"\n}\ncmd \"render-asset\" help=\"Render Asset\" {\n alias \"ra\"\n flag \"-p --prompt \" help=\"[required]\"\n flag \"--output-modalities \" help=\"options: text, image\" var=#true\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n}\ncmd \"stream-metadata\" help=\"Streamed events can contain text and an optional resource identifier in separate events.\" {\n alias \"sm\"\n}\ncmd \"tag1\" help=\"The first tag\" {\n cmd \"recent\" help=\"List recent test1 pages via tag1\" {\n flag \"-p --page \" help=\"[required]\"\n flag \"--query-param2 \" help=\"\"\"\n An [enum](https://enum.com) \"query parameter\"\n that is not easily described in a single line.\n\n **Available Values:**\n | Value | Description |\n |-------|-------------|\n | 0 | No data |\n | 1 | Partial |\n | 2 | Complete |\n (options: 0, 1, 2) [required]\n \"\"\"\n flag \"--header-param1 \" help=\"[required]\"\n }\n cmd \"auth\" help=\"\"\"\n This operation aims at testing available OAuth2 scopes collection:\n - only operation with oauth2 authorizationCode security flow\n - belongs to a subSDK\n \"\"\" {\n flag \"--access-token \" help=\"Security credential\"\n }\n cmd \"deprecated1\" help=\"Deprecated Operation\"\n cmd \"list-test1\" help=\"Get Test1\" {\n alias \"lt\"\n arg \"page\" help=\"integer value (or use --page)\"\n flag \"-p --page \" help=\"integer value (or pass it as the [page] argument)\"\n flag \"--query-param2 \" help=\"\"\"\n An [enum](https://enum.com) \"query parameter\"\n that is not easily described in a single line.\n\n **Available Values:**\n | Value | Description |\n |-------|-------------|\n | 0 | No data |\n | 1 | Partial |\n | 2 | Complete |\n (options: 0, 1, 2) [required]\n \"\"\"\n flag \"--header-param1 \" help=\"[required]\"\n flag \"-a --all\" help=\"Automatically paginate and fetch all results (streams NDJSON for JSON output)\"\n flag \"--max-pages \" help=\"Maximum number of pages to fetch when using --all (0 = no limit)\" default=0\n }\n cmd \"post-file-with-encoding\" help=\"Post File With Encoding\" {\n alias \"pfwe\"\n flag \"--file \" help=\"The file to upload (supports CSV, PNG, JPEG, or PDF)\"\n flag \"-a --attachment \" help=\"An optional binary attachment\"\n flag \"--file-name \" help=\"Optional custom file name\"\n flag \"--file-purpose \" help=\"Purpose of the file upload\"\n flag \"-m --metadata \" help=\"JSON metadata about the file\"\n }\n}\ncmd \"test-endpoint\" help=\"Test Endpoint\" {\n alias \"te\"\n arg \"test-name\" help=\"string value (or use --test-name)\"\n flag \"-t --test-name \" help=\"string value (or pass it as the [test-name] argument)\"\n flag \"--test \" help=\"[required]\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n}\ncmd \"test-enum-formats\" help=\"Test x-speakeasy-enums in different formats\" {\n alias \"tef\"\n flag \"--string-array-format \" help=\"String enum with x-speakeasy-enums as array (full coverage) (options: pending_review, approved_final, rejected_permanently, arch_x86, mobile_ios, custom_field) [required]\"\n flag \"--string-map-format \" help=\"String enum with x-speakeasy-enums as map (full coverage) (options: low_priority, medium_priority, high_priority, critical_urgent) [required]\"\n flag \"--string-partial-map-format \" help=\"String enum with x-speakeasy-enums as map (partial coverage) (options: draft_mode, under_review, published_live, archived_old) [required]\"\n flag \"--integer-map-format \" help=\"Integer enum with x-speakeasy-enums as map (full coverage) (options: 100, 200, 300, 400) [required]\"\n flag \"--integer-partial-map-format \" help=\"Integer enum with x-speakeasy-enums as map (partial coverage) (options: 1, 2, 3, 4, 5) [required]\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n}\ncmd \"update-user\" help=\"Update User\" {\n alias \"uu\"\n arg \"id\" help=\"string value (or use --id)\"\n flag \"-i --id \" help=\"string value (or pass it as the [id] argument)\"\n flag \"--user.id \" help=\"[required]\"\n flag \"--user.email \" help=\"[required]\"\n flag \"--user.first-name \" help=\"string value\"\n flag \"--user.last-name \" help=\"string value\"\n flag \"--user.age \" help=\"number value\"\n flag \"--user.postal-code \" help=\"string value\"\n flag \"--user.gender \" help=\"options: male, female, other\"\n flag \"--user.associated-ids \" help=\"list of values\" var=#true\n flag \"--user.metadata \" help=\"JSON object\"\n flag \"--user.metadata-any \" help=\"A metadata object with additionalProperties true (any type) - should be flattened\"\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n}\ncmd \"url-validation-stress-test\" help=\"Url Validation Stress Test\" {\n alias \"uvst\"\n}\ncmd \"validate\" help=\"Validate\"\ncmd \"version\" help=\"Print the CLI version\"\ncmd \"whoami\" help=\"Display current authentication and global parameter configuration\"\n", "invite": "cmd \"invite\" help=\"Invite a user by email\" {\n arg \"email\" help=\"Email address to invite\" required=#true var=#true\n flag \"--body \" help=\"Request body as JSON (advanced; merges with intent inputs, rejecting duplicate keys). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n flag \"--given-name \" help=\"First name to record\"\n flag \"--user-gender \" help=\"Gender to record (e.g. male, female, other)\" {\n suggestions \"male\" \"female\" \"other\"\n }\n}\n", "enroll": "cmd \"enroll\" help=\"Enroll a user by email\" {\n flag \"--body \" help=\"Request body as JSON (advanced; merges with intent inputs, rejecting duplicate keys). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n flag \"--enrollment-email \" help=\"Email address to enroll\"\n}\n", "render": "cmd \"render\" help=\"Render an image asset to a file\" {\n arg \"prompt\" help=\"Text prompt to render\" required=#true var=#true\n flag \"--body \" help=\"Request body as JSON (advanced; merges with intent inputs, rejecting duplicate keys). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n flag \"--out \" help=\"Write the image to this file (or into this directory). Default: ./render-{timestamp}-{rand}.{ext}\"\n flag \"--raw-response\" help=\"Print the raw API response instead of writing the image to a file\"\n}\n", @@ -131,6 +131,8 @@ var usageSchemas = map[string]string{ "pf": "cmd \"post-file\" help=\"Post File\" {\n alias \"pf\"\n flag \"-u --upload \" help=\"A file\"\n flag \"--output-file \" help=\"Save the response body to a file path (recommended for binary/file responses)\"\n flag \"--output-b64\" help=\"Encode binary response as base64 and print to stdout\"\n}\n", "render-asset": "cmd \"render-asset\" help=\"Render Asset\" {\n alias \"ra\"\n flag \"-p --prompt \" help=\"[required]\"\n flag \"--output-modalities \" help=\"options: text, image\" var=#true\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n}\n", "ra": "cmd \"render-asset\" help=\"Render Asset\" {\n alias \"ra\"\n flag \"-p --prompt \" help=\"[required]\"\n flag \"--output-modalities \" help=\"options: text, image\" var=#true\n flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\"\n flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\"\n}\n", + "stream-metadata": "cmd \"stream-metadata\" help=\"Streamed events can contain text and an optional resource identifier in separate events.\" {\n alias \"sm\"\n}\n", + "sm": "cmd \"stream-metadata\" help=\"Streamed events can contain text and an optional resource identifier in separate events.\" {\n alias \"sm\"\n}\n", "tag1": "cmd \"tag1\" help=\"The first tag\" {\n cmd \"recent\" help=\"List recent test1 pages via tag1\" {\n flag \"-p --page \" help=\"[required]\"\n flag \"--query-param2 \" help=\"\"\"\n An [enum](https://enum.com) \"query parameter\"\n that is not easily described in a single line.\n\n **Available Values:**\n | Value | Description |\n |-------|-------------|\n | 0 | No data |\n | 1 | Partial |\n | 2 | Complete |\n (options: 0, 1, 2) [required]\n \"\"\"\n flag \"--header-param1 \" help=\"[required]\"\n }\n cmd \"auth\" help=\"\"\"\n This operation aims at testing available OAuth2 scopes collection:\n - only operation with oauth2 authorizationCode security flow\n - belongs to a subSDK\n \"\"\" {\n flag \"--access-token \" help=\"Security credential\"\n }\n cmd \"deprecated1\" help=\"Deprecated Operation\"\n cmd \"list-test1\" help=\"Get Test1\" {\n alias \"lt\"\n arg \"page\" help=\"integer value (or use --page)\"\n flag \"-p --page \" help=\"integer value (or pass it as the [page] argument)\"\n flag \"--query-param2 \" help=\"\"\"\n An [enum](https://enum.com) \"query parameter\"\n that is not easily described in a single line.\n\n **Available Values:**\n | Value | Description |\n |-------|-------------|\n | 0 | No data |\n | 1 | Partial |\n | 2 | Complete |\n (options: 0, 1, 2) [required]\n \"\"\"\n flag \"--header-param1 \" help=\"[required]\"\n flag \"-a --all\" help=\"Automatically paginate and fetch all results (streams NDJSON for JSON output)\"\n flag \"--max-pages \" help=\"Maximum number of pages to fetch when using --all (0 = no limit)\" default=0\n }\n cmd \"post-file-with-encoding\" help=\"Post File With Encoding\" {\n alias \"pfwe\"\n flag \"--file \" help=\"The file to upload (supports CSV, PNG, JPEG, or PDF)\"\n flag \"-a --attachment \" help=\"An optional binary attachment\"\n flag \"--file-name \" help=\"Optional custom file name\"\n flag \"--file-purpose \" help=\"Purpose of the file upload\"\n flag \"-m --metadata \" help=\"JSON metadata about the file\"\n }\n}\n", "tag1 recent": "cmd \"recent\" help=\"List recent test1 pages via tag1\" {\n flag \"-p --page \" help=\"[required]\"\n flag \"--query-param2 \" help=\"\"\"\n An [enum](https://enum.com) \"query parameter\"\n that is not easily described in a single line.\n\n **Available Values:**\n | Value | Description |\n |-------|-------------|\n | 0 | No data |\n | 1 | Partial |\n | 2 | Complete |\n (options: 0, 1, 2) [required]\n \"\"\"\n flag \"--header-param1 \" help=\"[required]\"\n}\n", "tag1 auth": "cmd \"auth\" help=\"\"\"\n This operation aims at testing available OAuth2 scopes collection:\n - only operation with oauth2 authorizationCode security flow\n - belongs to a subSDK\n \"\"\" {\n flag \"--access-token \" help=\"Security credential\"\n}\n", diff --git a/zSDKs/sdk-cli/tests/mockserver/internal/sdk/models/operations/chat.go b/zSDKs/sdk-cli/tests/mockserver/internal/sdk/models/operations/chat.go index 88bceb55e..bc2e6be36 100644 --- a/zSDKs/sdk-cli/tests/mockserver/internal/sdk/models/operations/chat.go +++ b/zSDKs/sdk-cli/tests/mockserver/internal/sdk/models/operations/chat.go @@ -73,25 +73,33 @@ func (u ChatRequest) MarshalJSON() ([]byte, error) { return nil, errors.New("could not marshal union type ChatRequest: all fields are null") } -type Data struct { - Content *string `json:"content,omitempty"` +type ChatData struct { + Content *string `json:"content,omitempty"` + ResourceID *string `json:"resource_id,omitempty"` } -func (o *Data) GetContent() *string { +func (o *ChatData) GetContent() *string { if o == nil { return nil } return o.Content } +func (o *ChatData) GetResourceID() *string { + if o == nil { + return nil + } + return o.ResourceID +} + // ChatStream - A stream containing chat completion tokens type ChatStream struct { - Data Data `json:"data"` + Data ChatData `json:"data"` } -func (o *ChatStream) GetData() Data { +func (o *ChatStream) GetData() ChatData { if o == nil { - return Data{} + return ChatData{} } return o.Data } diff --git a/zSDKs/sdk-cli/tests/mockserver/internal/sdk/models/operations/streammetadata.go b/zSDKs/sdk-cli/tests/mockserver/internal/sdk/models/operations/streammetadata.go new file mode 100644 index 000000000..9f0903f06 --- /dev/null +++ b/zSDKs/sdk-cli/tests/mockserver/internal/sdk/models/operations/streammetadata.go @@ -0,0 +1,63 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package operations + +import ( + "mockserver/internal/sdk/models/components" + "mockserver/internal/sdk/types/stream" +) + +type StreamMetadataData struct { + Content *string `json:"content,omitempty"` + ResourceID *string `json:"resource_id,omitempty"` +} + +func (o *StreamMetadataData) GetContent() *string { + if o == nil { + return nil + } + return o.Content +} + +func (o *StreamMetadataData) GetResourceID() *string { + if o == nil { + return nil + } + return o.ResourceID +} + +// StreamMetadataResponseBody - Streamed resource events. +type StreamMetadataResponseBody struct { + Data StreamMetadataData `json:"data"` +} + +func (o *StreamMetadataResponseBody) GetData() StreamMetadataData { + if o == nil { + return StreamMetadataData{} + } + return o.Data +} + +func (o StreamMetadataResponseBody) GetEventEncoding(event string) (string, error) { + return "application/json", nil +} + +type StreamMetadataResponse struct { + HTTPMeta components.HTTPMetadata `json:"-"` + // Streamed resource events. + Object *stream.EventStream[StreamMetadataResponseBody] +} + +func (o *StreamMetadataResponse) GetHTTPMeta() components.HTTPMetadata { + if o == nil { + return components.HTTPMetadata{} + } + return o.HTTPMeta +} + +func (o *StreamMetadataResponse) GetObject() *stream.EventStream[StreamMetadataResponseBody] { + if o == nil { + return nil + } + return o.Object +}