From 45b24240de42f54af4a389ed753aae3d00bc82a5 Mon Sep 17 00:00:00 2001 From: Hugo martins Date: Wed, 8 Jul 2026 03:03:22 +0200 Subject: [PATCH 1/4] feat: dynamic display_name for triggered runs (#4259) Let callers set a human-readable label on a run at trigger time, so fanned-out child/bulk runs are distinguishable in the dashboard instead of all sharing the generated - name. Engine (pkg/repository): - NormalizeDisplayName: trim; empty/whitespace -> unset (generated fallback); truncate to 255 runes (UTF-8/rune-safe). Applied at both SDK and REST ingestion. - Single-task runs -> v1_task.display_name; multi-step DAGs -> v1_dag.display_name (DAG step tasks keep generated names). Excluded from all dedup/idempotency keys, so durable/child re-triggers reuse the first name (first-name-wins). REST: display_name on the trigger endpoint + admin-path normalization. Proto/OpenAPI: display_name added (trigger.proto #11, workflows.proto #6) + regen. SDKs (Python, TypeScript, Go, Ruby): display_name on every run surface (run / run_no_wait / aio variants, bulk & run_many per-item, child spawns). Python: carried through _create_workflow_run_request so the value actually reaches gRPC on the real run path. Docs: new "Run Names" guide + cross-links; CHANGELOG entry. Tests: engine unit (NormalizeDisplayName, idempotency-key invariance) + integration (single/DAG/fallback/whitespace/255-rune/run_many/first-name-wins), REST handler, and per-SDK request-builder tests. Co-Authored-By: Claude Opus 4.8 (1M context) --- CHANGELOG.md | 5 + .../components/schemas/v1/workflow_run.yaml | 3 + api-contracts/v1/shared/trigger.proto | 3 + api-contracts/v1/workflows.proto | 3 + .../handlers/v1/workflow-runs/trigger.go | 1 + api/v1/server/oas/gen/openapi.gen.go | 429 +++++++------- .../src/lib/api/generated/data-contracts.ts | 2 + frontend/docs/pages/v1/_meta.js | 1 + .../docs/pages/v1/additional-metadata.mdx | 6 + frontend/docs/pages/v1/child-spawning.mdx | 6 + frontend/docs/pages/v1/run-names.mdx | 85 +++ .../services/admin/contracts/workflows.pb.go | 2 +- .../admin/contracts/workflows_grpc.pb.go | 2 +- internal/services/admin/v1/server.go | 1 + internal/services/admin/v1/server_test.go | 35 ++ .../dispatcher/contracts/dispatcher.pb.go | 2 +- .../contracts/dispatcher_grpc.pb.go | 2 +- .../services/ingestor/contracts/events.pb.go | 2 +- .../ingestor/contracts/events_grpc.pb.go | 2 +- .../services/shared/proto/v1/condition.pb.go | 2 +- .../services/shared/proto/v1/dispatcher.pb.go | 2 +- .../shared/proto/v1/dispatcher_grpc.pb.go | 2 +- .../services/shared/proto/v1/trigger.pb.go | 75 ++- .../services/shared/proto/v1/workflows.pb.go | 552 +++++++++--------- .../shared/proto/v1/workflows_grpc.pb.go | 2 +- pkg/client/admin.go | 17 + pkg/client/admin_display_name_test.go | 37 ++ pkg/client/rest/gen.go | 5 +- pkg/repository/durable_events_test.go | 35 ++ pkg/repository/task.go | 10 +- pkg/repository/trigger.go | 44 +- .../trigger_display_name_integration_test.go | 364 ++++++++++++ pkg/repository/trigger_test.go | 35 ++ pkg/worker/context.go | 4 + sdks/go/client.go | 4 + sdks/go/display_name_test.go | 27 + sdks/go/durable_child.go | 1 + sdks/go/workflow.go | 14 + sdks/python/CHANGELOG.md | 6 + sdks/python/hatchet_sdk/clients/admin.py | 3 + .../contracts/v1/shared/trigger_pb2.py | 18 +- .../contracts/v1/shared/trigger_pb2.pyi | 8 +- .../hatchet_sdk/contracts/v1/workflows_pb2.py | 94 +-- .../contracts/v1/workflows_pb2.pyi | 12 +- sdks/python/hatchet_sdk/runnables/workflow.py | 30 + sdks/python/hatchet_sdk/types/trigger.py | 1 + .../tests/unit/test_trigger_display_name.py | 73 +++ sdks/ruby/src/CHANGELOG.md | 6 + .../src/lib/hatchet/clients/grpc/admin.rb | 2 + .../hatchet/contracts/v1/shared/trigger_pb.rb | 2 +- .../lib/hatchet/contracts/v1/workflows_pb.rb | 2 +- sdks/ruby/src/lib/hatchet/trigger_options.rb | 9 +- sdks/ruby/src/sig/hatchet/trigger_options.rbs | 4 +- .../spec/hatchet/clients/grpc/admin_spec.rb | 66 +++ .../src/spec/hatchet/trigger_options_spec.rb | 21 + sdks/typescript/CHANGELOG.md | 6 + .../src/protoc/google/protobuf/timestamp.ts | 43 +- .../src/protoc/v1/shared/condition.ts | 212 +++---- .../src/protoc/v1/shared/trigger.ts | 25 +- sdks/typescript/src/protoc/v1/workflows.ts | 25 +- sdks/typescript/src/v1/client/admin.test.ts | 36 ++ sdks/typescript/src/v1/client/admin.ts | 2 + .../src/v1/client/worker/context.ts | 1 + sdks/typescript/src/v1/declaration.ts | 7 + 64 files changed, 1796 insertions(+), 742 deletions(-) create mode 100644 frontend/docs/pages/v1/run-names.mdx create mode 100644 internal/services/admin/v1/server_test.go create mode 100644 pkg/client/admin_display_name_test.go create mode 100644 pkg/repository/trigger_display_name_integration_test.go create mode 100644 sdks/go/display_name_test.go create mode 100644 sdks/python/tests/unit/test_trigger_display_name.py create mode 100644 sdks/ruby/src/spec/hatchet/clients/grpc/admin_spec.rb create mode 100644 sdks/ruby/src/spec/hatchet/trigger_options_spec.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index b0f1f9e672..0d8c87f0ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## [Unreleased] + +### Added +- Runs can now be given a custom `display_name` at trigger time (via any SDK's run/run-many/child-spawn options or the REST trigger endpoint), so fanned-out child runs are identifiable at a glance in the dashboard instead of sharing a generated `-` label. Single-task runs carry the name on the task; multi-step DAG runs carry it on the DAG (steps keep their generated names). Omitting the field (or passing empty/whitespace) preserves the previous generated-name behavior, and names longer than 255 characters are stored truncated rather than rejected ([#4259](https://github.com/hatchet-dev/hatchet/issues/4259)). + ## [0.89.0] - 2026-06-09 Hatchet v0.89.0 introduces a range of updates to the platform, consisting largely of performance improvements and bug fixes to the engine, alongside several user-experience changes to the dashboard. diff --git a/api-contracts/openapi/components/schemas/v1/workflow_run.yaml b/api-contracts/openapi/components/schemas/v1/workflow_run.yaml index 477488e71f..471ffad88e 100644 --- a/api-contracts/openapi/components/schemas/v1/workflow_run.yaml +++ b/api-contracts/openapi/components/schemas/v1/workflow_run.yaml @@ -141,6 +141,9 @@ V1TriggerWorkflowRunRequest: priority: type: integer description: The priority of the workflow run. + displayName: + type: string + description: A custom display name for the run. Falls back to a generated name if unset. required: - workflowName - input diff --git a/api-contracts/v1/shared/trigger.proto b/api-contracts/v1/shared/trigger.proto index ad8913a43d..9470224e41 100644 --- a/api-contracts/v1/shared/trigger.proto +++ b/api-contracts/v1/shared/trigger.proto @@ -74,4 +74,7 @@ message TriggerWorkflowRequest { // (optional) the desired worker labels for the workflow run, which will be used to determine which workers can pick up the workflow's tasks. if not set, defaults to an empty set of labels, which means any worker can pick up the tasks. map desired_worker_labels = 10; + + // (optional) a custom display name for the run; falls back to "-" if unset + optional string display_name = 11; } diff --git a/api-contracts/v1/workflows.proto b/api-contracts/v1/workflows.proto index e155664f61..62392d3990 100644 --- a/api-contracts/v1/workflows.proto +++ b/api-contracts/v1/workflows.proto @@ -50,6 +50,9 @@ message TriggerWorkflowRunRequest { bytes additional_metadata = 3; optional int32 priority = 4; map desired_worker_labels = 5; + + // (optional) a custom display name for the run; falls back to a generated name if unset + optional string display_name = 6; } message TriggerWorkflowRunResponse { diff --git a/api/v1/server/handlers/v1/workflow-runs/trigger.go b/api/v1/server/handlers/v1/workflow-runs/trigger.go index 34fa6bf852..644cc712af 100644 --- a/api/v1/server/handlers/v1/workflow-runs/trigger.go +++ b/api/v1/server/handlers/v1/workflow-runs/trigger.go @@ -63,6 +63,7 @@ func (t *V1WorkflowRunsService) V1WorkflowRunCreate(ctx echo.Context, request ge Input: inputBytes, AdditionalMetadata: additionalMetadataBytes, Priority: priority, + DisplayName: request.Body.DisplayName, } resp, err := t.proxyTrigger.Do( diff --git a/api/v1/server/oas/gen/openapi.gen.go b/api/v1/server/oas/gen/openapi.gen.go index 9fd0c94e37..7842110da7 100644 --- a/api/v1/server/oas/gen/openapi.gen.go +++ b/api/v1/server/oas/gen/openapi.gen.go @@ -2062,7 +2062,10 @@ type V1TaskTimingList struct { // V1TriggerWorkflowRunRequest defines model for V1TriggerWorkflowRunRequest. type V1TriggerWorkflowRunRequest struct { AdditionalMetadata *map[string]interface{} `json:"additionalMetadata,omitempty"` - Input map[string]interface{} `json:"input"` + + // DisplayName A custom display name for the run. Falls back to a generated name if unset. + DisplayName *string `json:"displayName,omitempty"` + Input map[string]interface{} `json:"input"` // Priority The priority of the workflow run. Priority *int `json:"priority,omitempty"` @@ -17671,218 +17674,218 @@ var swaggerSpec = []string{ "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", - "BQAA//+Kc+/za4UDAA==", + "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", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/frontend/app/src/lib/api/generated/data-contracts.ts b/frontend/app/src/lib/api/generated/data-contracts.ts index c7cbb38954..350f28742e 100644 --- a/frontend/app/src/lib/api/generated/data-contracts.ts +++ b/frontend/app/src/lib/api/generated/data-contracts.ts @@ -658,6 +658,8 @@ export interface V1TriggerWorkflowRunRequest { additionalMetadata?: object; /** The priority of the workflow run. */ priority?: number; + /** A custom display name for the run. Falls back to a generated name if unset. */ + displayName?: string; } export interface V1WorkflowRun { diff --git a/frontend/docs/pages/v1/_meta.js b/frontend/docs/pages/v1/_meta.js index 429226f98a..fe2075098c 100644 --- a/frontend/docs/pages/v1/_meta.js +++ b/frontend/docs/pages/v1/_meta.js @@ -39,6 +39,7 @@ export default { concurrency: "Concurrency", "rate-limits": "Rate Limits", priority: "Priority", + "run-names": "Run Names", "--durable-workflows-section": { title: "Durable Execution", type: "separator", diff --git a/frontend/docs/pages/v1/additional-metadata.mdx b/frontend/docs/pages/v1/additional-metadata.mdx index 0b5e0d112e..2bfeade968 100644 --- a/frontend/docs/pages/v1/additional-metadata.mdx +++ b/frontend/docs/pages/v1/additional-metadata.mdx @@ -13,6 +13,12 @@ Hatchet allows you to attach arbitrary key-value string pairs to events and task runs. + + If you only want a human-readable label to tell fanned-out runs apart in the + dashboard, see [Run Names](./run-names.mdx) — it sets the run's `display_name` + directly instead of relying on metadata. + + You can attach additional metadata when pushing events or triggering task runs using the Hatchet client libraries: diff --git a/frontend/docs/pages/v1/child-spawning.mdx b/frontend/docs/pages/v1/child-spawning.mdx index c2ff543488..e3e9c3d9e9 100644 --- a/frontend/docs/pages/v1/child-spawning.mdx +++ b/frontend/docs/pages/v1/child-spawning.mdx @@ -10,6 +10,12 @@ import FanoutDiagram from "@/components/FanoutDiagram"; A task can spawn child tasks at runtime — including other durable tasks or entire DAG workflows. Children run independently on any available worker, and the parent can wait for their results before continuing. You can spawn children out of any task (durable or not). + + Spawning many children at once? Give each a [display name](./run-names.mdx) so + they're identifiable at a glance in the dashboard instead of sharing a generated + name. + + While child spawning is not unique to durable tasks, we often recommend using durable tasks when spawning children is the main responsibility (or one of the diff --git a/frontend/docs/pages/v1/run-names.mdx b/frontend/docs/pages/v1/run-names.mdx new file mode 100644 index 0000000000..0c3f9e6c49 --- /dev/null +++ b/frontend/docs/pages/v1/run-names.mdx @@ -0,0 +1,85 @@ +import { Callout, Tabs } from "nextra/components"; +import UniversalTabs from "../../components/UniversalTabs"; + +# Naming runs with a custom display name + +By default, each run in Hatchet is labelled with a generated name of the form `-` (for example, `resolve-subprocessor-info-1782146942603`). When a parent fans out many child runs in a single batch, they all share the same step id and batch timestamp, so the runs list renders several identically-named rows and you have to open each run's input to tell them apart. + +You can instead set a human-readable **display name** at trigger time. The dashboard renders it automatically in the runs list, the run detail header, and the children list — no other configuration required. + + + +The display name is applied to the **run**: + +- For a **single-task** workflow, it lands on the task (the task _is_ the run). +- For a **multi-step DAG**, it lands on the DAG run; the DAG's step tasks keep their generated names. + +Omitting the field (or passing an empty/whitespace value) preserves the default generated name. A name longer than 255 characters is stored truncated, never rejected. + + + +## Setting a display name + +Pass the display name in the options you already use to trigger a run. This works for top-level runs, `run_many` / bulk triggers (each item gets its own name), and child spawns (each child gets its own name). + + + + +```python +# Top-level run +workflow.run(input, display_name="Acme Corp") + +# Per-item names in a bulk run +workflow.run_many([ + workflow.create_bulk_run_item(input=input_a, display_name="Acme Corp"), + workflow.create_bulk_run_item(input=input_b, display_name="Globex"), +]) +``` + + + + +```typescript +// Top-level run +await workflow.run(input, { displayName: "Acme Corp" }); + +// Spawning a child with its own name +await ctx.runChild(childWorkflow, input, { displayName: "Acme Corp" }); +``` + + + + +```go +// Top-level run +_, err := client.Run(ctx, "my-workflow", input, hatchet.WithRunDisplayName("Acme Corp")) +``` + + + + +```ruby +# Top-level run +workflow.run(input, options: { display_name: "Acme Corp" }) +``` + + + + +## REST + +The REST trigger endpoint accepts the same field: + +```json +POST /api/v1/stable/tenants/{tenant}/workflow-runs/trigger +{ + "workflowName": "my-workflow", + "input": { ... }, + "displayName": "Acme Corp" +} +``` + +## Related + +- [Additional metadata](./additional-metadata.mdx) — attach arbitrary key/value metadata to a run, which is filterable and searchable (the display name is display-only). +- [Child spawning](./child-spawning.mdx) — fanning out child runs, the most common place a per-run display name helps. diff --git a/internal/services/admin/contracts/workflows.pb.go b/internal/services/admin/contracts/workflows.pb.go index d946314404..40eeef1a0f 100644 --- a/internal/services/admin/contracts/workflows.pb.go +++ b/internal/services/admin/contracts/workflows.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 -// protoc v5.29.3 +// protoc v7.35.1 // source: workflows.proto package contracts diff --git a/internal/services/admin/contracts/workflows_grpc.pb.go b/internal/services/admin/contracts/workflows_grpc.pb.go index e0a8aa6f11..a79d47096e 100644 --- a/internal/services/admin/contracts/workflows_grpc.pb.go +++ b/internal/services/admin/contracts/workflows_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 -// - protoc v5.29.3 +// - protoc v7.35.1 // source: workflows.proto package contracts diff --git a/internal/services/admin/v1/server.go b/internal/services/admin/v1/server.go index 6873d51c2c..e14c7831f1 100644 --- a/internal/services/admin/v1/server.go +++ b/internal/services/admin/v1/server.go @@ -565,6 +565,7 @@ func (a *AdminServiceImpl) newTriggerOpt( WorkflowName: req.WorkflowName, Data: req.Input, AdditionalMetadata: req.AdditionalMetadata, + DisplayName: v1.NormalizeDisplayName(req.DisplayName), } if len(req.DesiredWorkerLabels) > 0 { diff --git a/internal/services/admin/v1/server_test.go b/internal/services/admin/v1/server_test.go new file mode 100644 index 0000000000..5d176076ee --- /dev/null +++ b/internal/services/admin/v1/server_test.go @@ -0,0 +1,35 @@ +package v1 + +import ( + "context" + "testing" + + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + contracts "github.com/hatchet-dev/hatchet/internal/services/shared/proto/v1" +) + +func Test_newTriggerOpt_normalizes_display_name(t *testing.T) { + a := &AdminServiceImpl{} + name := " Acme Corp " + + opt, err := a.newTriggerOpt(context.Background(), uuid.New(), &contracts.TriggerWorkflowRunRequest{ + WorkflowName: "my-workflow", + DisplayName: &name, + }) + require.NoError(t, err) + require.NotNil(t, opt.DisplayName, "REST display name should be carried onto the trigger opt") + assert.Equal(t, "Acme Corp", *opt.DisplayName, "REST display name is trimmed via NormalizeDisplayName") +} + +func Test_newTriggerOpt_omits_display_name_when_unset(t *testing.T) { + a := &AdminServiceImpl{} + + opt, err := a.newTriggerOpt(context.Background(), uuid.New(), &contracts.TriggerWorkflowRunRequest{ + WorkflowName: "my-workflow", + }) + require.NoError(t, err) + assert.Nil(t, opt.DisplayName, "omitted display name stays unset so the run falls back to a generated name") +} diff --git a/internal/services/dispatcher/contracts/dispatcher.pb.go b/internal/services/dispatcher/contracts/dispatcher.pb.go index a6d8c8d42c..40805de64a 100644 --- a/internal/services/dispatcher/contracts/dispatcher.pb.go +++ b/internal/services/dispatcher/contracts/dispatcher.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 -// protoc v5.29.3 +// protoc v7.35.1 // source: dispatcher.proto package contracts diff --git a/internal/services/dispatcher/contracts/dispatcher_grpc.pb.go b/internal/services/dispatcher/contracts/dispatcher_grpc.pb.go index 3f5c21515d..3ec1db8d4c 100644 --- a/internal/services/dispatcher/contracts/dispatcher_grpc.pb.go +++ b/internal/services/dispatcher/contracts/dispatcher_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 -// - protoc v5.29.3 +// - protoc v7.35.1 // source: dispatcher.proto package contracts diff --git a/internal/services/ingestor/contracts/events.pb.go b/internal/services/ingestor/contracts/events.pb.go index b1e0063a8f..41846ecc07 100644 --- a/internal/services/ingestor/contracts/events.pb.go +++ b/internal/services/ingestor/contracts/events.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 -// protoc v5.29.3 +// protoc v7.35.1 // source: events.proto package contracts diff --git a/internal/services/ingestor/contracts/events_grpc.pb.go b/internal/services/ingestor/contracts/events_grpc.pb.go index 1c239b06f8..029a81c344 100644 --- a/internal/services/ingestor/contracts/events_grpc.pb.go +++ b/internal/services/ingestor/contracts/events_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 -// - protoc v5.29.3 +// - protoc v7.35.1 // source: events.proto package contracts diff --git a/internal/services/shared/proto/v1/condition.pb.go b/internal/services/shared/proto/v1/condition.pb.go index 23f819269f..ae7143fd02 100644 --- a/internal/services/shared/proto/v1/condition.pb.go +++ b/internal/services/shared/proto/v1/condition.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 -// protoc v5.29.3 +// protoc v7.35.1 // source: v1/shared/condition.proto package v1 diff --git a/internal/services/shared/proto/v1/dispatcher.pb.go b/internal/services/shared/proto/v1/dispatcher.pb.go index 7a7e5673cc..ebf0fb6831 100644 --- a/internal/services/shared/proto/v1/dispatcher.pb.go +++ b/internal/services/shared/proto/v1/dispatcher.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 -// protoc v5.29.3 +// protoc v7.35.1 // source: v1/dispatcher.proto package v1 diff --git a/internal/services/shared/proto/v1/dispatcher_grpc.pb.go b/internal/services/shared/proto/v1/dispatcher_grpc.pb.go index 953cce76b8..55ad08f6f8 100644 --- a/internal/services/shared/proto/v1/dispatcher_grpc.pb.go +++ b/internal/services/shared/proto/v1/dispatcher_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 -// - protoc v5.29.3 +// - protoc v7.35.1 // source: v1/dispatcher.proto package v1 diff --git a/internal/services/shared/proto/v1/trigger.pb.go b/internal/services/shared/proto/v1/trigger.pb.go index 9769ffbe82..c46431c4aa 100644 --- a/internal/services/shared/proto/v1/trigger.pb.go +++ b/internal/services/shared/proto/v1/trigger.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 -// protoc v5.29.3 +// protoc v7.35.1 // source: v1/shared/trigger.proto package v1 @@ -198,6 +198,8 @@ type TriggerWorkflowRequest struct { Priority *int32 `protobuf:"varint,9,opt,name=priority,proto3,oneof" json:"priority,omitempty"` // (optional) the desired worker labels for the workflow run, which will be used to determine which workers can pick up the workflow's tasks. if not set, defaults to an empty set of labels, which means any worker can pick up the tasks. DesiredWorkerLabels map[string]*DesiredWorkerLabels `protobuf:"bytes,10,rep,name=desired_worker_labels,json=desiredWorkerLabels,proto3" json:"desired_worker_labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // (optional) a custom display name for the run; falls back to "-" if unset + DisplayName *string `protobuf:"bytes,11,opt,name=display_name,json=displayName,proto3,oneof" json:"display_name,omitempty"` } func (x *TriggerWorkflowRequest) Reset() { @@ -302,6 +304,13 @@ func (x *TriggerWorkflowRequest) GetDesiredWorkerLabels() map[string]*DesiredWor return nil } +func (x *TriggerWorkflowRequest) GetDisplayName() string { + if x != nil && x.DisplayName != nil { + return *x.DisplayName + } + return "" +} + var File_v1_shared_trigger_proto protoreflect.FileDescriptor var file_v1_shared_trigger_proto_rawDesc = []byte{ @@ -324,7 +333,7 @@ var file_v1_shared_trigger_proto_rawDesc = []byte{ 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x69, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x42, - 0x09, 0x0a, 0x07, 0x5f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0xc8, 0x05, 0x0a, 0x16, 0x54, + 0x09, 0x0a, 0x07, 0x5f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0x81, 0x06, 0x0a, 0x16, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x70, @@ -354,35 +363,39 @@ var file_v1_shared_trigger_proto_rawDesc = []byte{ 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x13, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, - 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x5f, 0x0a, - 0x18, 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, - 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2d, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x76, 0x31, 0x2e, - 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, - 0x65, 0x6c, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0c, - 0x0a, 0x0a, 0x5f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x42, 0x1e, 0x0a, 0x1c, - 0x5f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x72, 0x75, 0x6e, - 0x5f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x42, 0x0e, 0x0a, 0x0c, - 0x5f, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x0c, 0x0a, 0x0a, - 0x5f, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x61, - 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x77, - 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x70, 0x72, 0x69, - 0x6f, 0x72, 0x69, 0x74, 0x79, 0x2a, 0x85, 0x01, 0x0a, 0x15, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, - 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, - 0x09, 0x0a, 0x05, 0x45, 0x51, 0x55, 0x41, 0x4c, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, - 0x54, 0x5f, 0x45, 0x51, 0x55, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x47, 0x52, 0x45, - 0x41, 0x54, 0x45, 0x52, 0x5f, 0x54, 0x48, 0x41, 0x4e, 0x10, 0x02, 0x12, 0x19, 0x0a, 0x15, 0x47, - 0x52, 0x45, 0x41, 0x54, 0x45, 0x52, 0x5f, 0x54, 0x48, 0x41, 0x4e, 0x5f, 0x4f, 0x52, 0x5f, 0x45, - 0x51, 0x55, 0x41, 0x4c, 0x10, 0x03, 0x12, 0x0d, 0x0a, 0x09, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x54, - 0x48, 0x41, 0x4e, 0x10, 0x04, 0x12, 0x16, 0x0a, 0x12, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x54, 0x48, - 0x41, 0x4e, 0x5f, 0x4f, 0x52, 0x5f, 0x45, 0x51, 0x55, 0x41, 0x4c, 0x10, 0x05, 0x42, 0x42, 0x5a, - 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x74, 0x63, - 0x68, 0x65, 0x74, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x2f, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, - 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x26, 0x0a, + 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0b, 0x20, + 0x01, 0x28, 0x09, 0x48, 0x07, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, + 0x6d, 0x65, 0x88, 0x01, 0x01, 0x1a, 0x5f, 0x0a, 0x18, 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, + 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x2d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x57, + 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x70, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x5f, 0x69, 0x64, 0x42, 0x1e, 0x0a, 0x1c, 0x5f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, + 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x5f, 0x69, 0x64, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x69, + 0x6e, 0x64, 0x65, 0x78, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x6b, + 0x65, 0x79, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, + 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x64, + 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x42, 0x0f, 0x0a, + 0x0d, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x2a, 0x85, + 0x01, 0x0a, 0x15, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x43, 0x6f, + 0x6d, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x51, 0x55, 0x41, + 0x4c, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x54, 0x5f, 0x45, 0x51, 0x55, 0x41, 0x4c, + 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x47, 0x52, 0x45, 0x41, 0x54, 0x45, 0x52, 0x5f, 0x54, 0x48, + 0x41, 0x4e, 0x10, 0x02, 0x12, 0x19, 0x0a, 0x15, 0x47, 0x52, 0x45, 0x41, 0x54, 0x45, 0x52, 0x5f, + 0x54, 0x48, 0x41, 0x4e, 0x5f, 0x4f, 0x52, 0x5f, 0x45, 0x51, 0x55, 0x41, 0x4c, 0x10, 0x03, 0x12, + 0x0d, 0x0a, 0x09, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x54, 0x48, 0x41, 0x4e, 0x10, 0x04, 0x12, 0x16, + 0x0a, 0x12, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x54, 0x48, 0x41, 0x4e, 0x5f, 0x4f, 0x52, 0x5f, 0x45, + 0x51, 0x55, 0x41, 0x4c, 0x10, 0x05, 0x42, 0x42, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x2d, 0x64, 0x65, 0x76, + 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, + 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( diff --git a/internal/services/shared/proto/v1/workflows.pb.go b/internal/services/shared/proto/v1/workflows.pb.go index bf3d29cb9a..c4d22cd4d2 100644 --- a/internal/services/shared/proto/v1/workflows.pb.go +++ b/internal/services/shared/proto/v1/workflows.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 -// protoc v5.29.3 +// protoc v7.35.1 // source: v1/workflows.proto package v1 @@ -534,6 +534,8 @@ type TriggerWorkflowRunRequest struct { AdditionalMetadata []byte `protobuf:"bytes,3,opt,name=additional_metadata,json=additionalMetadata,proto3" json:"additional_metadata,omitempty"` Priority *int32 `protobuf:"varint,4,opt,name=priority,proto3,oneof" json:"priority,omitempty"` DesiredWorkerLabels map[string]*DesiredWorkerLabels `protobuf:"bytes,5,rep,name=desired_worker_labels,json=desiredWorkerLabels,proto3" json:"desired_worker_labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // (optional) a custom display name for the run; falls back to a generated name if unset + DisplayName *string `protobuf:"bytes,6,opt,name=display_name,json=displayName,proto3,oneof" json:"display_name,omitempty"` } func (x *TriggerWorkflowRunRequest) Reset() { @@ -603,6 +605,13 @@ func (x *TriggerWorkflowRunRequest) GetDesiredWorkerLabels() map[string]*Desired return nil } +func (x *TriggerWorkflowRunRequest) GetDisplayName() string { + if x != nil && x.DisplayName != nil { + return *x.DisplayName + } + return "" +} + type TriggerWorkflowRunResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1626,7 +1635,7 @@ var file_v1_workflows_proto_rawDesc = []byte{ 0x73, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x64, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x64, 0x54, 0x61, 0x73, - 0x6b, 0x73, 0x22, 0x82, 0x03, 0x0a, 0x19, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x57, 0x6f, + 0x6b, 0x73, 0x22, 0xbb, 0x03, 0x0a, 0x19, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, @@ -1643,275 +1652,278 @@ var file_v1_workflows_proto_rawDesc = []byte{ 0x77, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x13, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x57, 0x6f, 0x72, - 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x5f, 0x0a, 0x18, 0x44, 0x65, 0x73, - 0x69, 0x72, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x69, - 0x72, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x70, - 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x3d, 0x0a, 0x1a, 0x54, 0x72, 0x69, 0x67, 0x67, - 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, - 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x22, 0x7a, 0x0a, 0x18, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, - 0x44, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, 0x61, - 0x73, 0x6b, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, - 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6e, - 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x5f, - 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, - 0x49, 0x64, 0x22, 0x7b, 0x0a, 0x19, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x44, 0x75, 0x72, 0x61, - 0x62, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x28, 0x0a, 0x10, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, 0x61, 0x73, 0x6b, 0x45, - 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, - 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, - 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x5f, 0x69, 0x64, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x49, 0x64, 0x22, - 0xdd, 0x05, 0x0a, 0x1c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, - 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, - 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, - 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x72, 0x6f, 0x6e, 0x5f, - 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, - 0x63, 0x72, 0x6f, 0x6e, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x73, 0x12, 0x28, 0x0a, 0x05, - 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x76, 0x31, - 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x70, 0x74, 0x73, 0x52, - 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x31, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, - 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, - 0x2e, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0b, 0x63, 0x6f, - 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x22, 0x0a, 0x0a, 0x63, 0x72, 0x6f, - 0x6e, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, - 0x09, 0x63, 0x72, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x88, 0x01, 0x01, 0x12, 0x3f, 0x0a, - 0x0f, 0x6f, 0x6e, 0x5f, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, - 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x70, 0x74, 0x73, 0x48, 0x01, 0x52, 0x0d, 0x6f, 0x6e, - 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x88, 0x01, 0x01, 0x12, 0x2f, - 0x0a, 0x06, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, - 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x69, 0x63, 0x6b, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, - 0x67, 0x79, 0x48, 0x02, 0x52, 0x06, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x79, 0x88, 0x01, 0x01, 0x12, - 0x2e, 0x0a, 0x10, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x72, 0x69, 0x6f, 0x72, - 0x69, 0x74, 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x48, 0x03, 0x52, 0x0f, 0x64, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x88, 0x01, 0x01, 0x12, - 0x38, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x61, - 0x72, 0x72, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, - 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x63, 0x75, - 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x41, 0x72, 0x72, 0x12, 0x3a, 0x0a, 0x0f, 0x64, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x0d, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, - 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x0e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x69, - 0x6c, 0x74, 0x65, 0x72, 0x73, 0x12, 0x2f, 0x0a, 0x11, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x6a, - 0x73, 0x6f, 0x6e, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0c, - 0x48, 0x04, 0x52, 0x0f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x4a, 0x73, 0x6f, 0x6e, 0x53, 0x63, 0x68, - 0x65, 0x6d, 0x61, 0x88, 0x01, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x63, 0x72, 0x6f, 0x6e, 0x5f, - 0x69, 0x6e, 0x70, 0x75, 0x74, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x6f, 0x6e, 0x5f, 0x66, 0x61, 0x69, - 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x73, 0x74, - 0x69, 0x63, 0x6b, 0x79, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, - 0x5f, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x69, 0x6e, - 0x70, 0x75, 0x74, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x22, - 0x70, 0x0a, 0x0d, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, - 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, - 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, - 0x61, 0x64, 0x88, 0x01, 0x01, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, - 0x64, 0x22, 0xb7, 0x01, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, - 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x1e, 0x0a, 0x08, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x75, 0x6e, 0x73, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x07, 0x6d, 0x61, 0x78, 0x52, 0x75, 0x6e, 0x73, 0x88, 0x01, - 0x01, 0x12, 0x48, 0x0a, 0x0e, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, - 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x76, 0x31, 0x2e, 0x43, - 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x53, - 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x48, 0x01, 0x52, 0x0d, 0x6c, 0x69, 0x6d, 0x69, 0x74, - 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, - 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x75, 0x6e, 0x73, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x6c, 0x69, 0x6d, - 0x69, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x22, 0x85, 0x07, 0x0a, 0x0e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x70, 0x74, 0x73, 0x12, 0x1f, - 0x0a, 0x0b, 0x72, 0x65, 0x61, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x61, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x49, 0x64, 0x12, - 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, - 0x75, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, - 0x74, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x72, - 0x65, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x38, 0x0a, - 0x0b, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x18, 0x07, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, - 0x73, 0x6b, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x0a, 0x72, 0x61, 0x74, - 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x12, 0x49, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x65, - 0x72, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, - 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x70, - 0x74, 0x73, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, - 0x6c, 0x73, 0x12, 0x2a, 0x0a, 0x0e, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x5f, 0x66, 0x61, - 0x63, 0x74, 0x6f, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x02, 0x48, 0x00, 0x52, 0x0d, 0x62, 0x61, - 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x46, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x33, - 0x0a, 0x13, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x65, - 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x48, 0x01, 0x52, 0x11, 0x62, - 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x4d, 0x61, 0x78, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, - 0x88, 0x01, 0x01, 0x12, 0x31, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, - 0x63, 0x79, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, - 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, - 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x37, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x76, 0x31, 0x2e, - 0x54, 0x61, 0x73, 0x6b, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x48, 0x02, - 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x88, 0x01, 0x01, 0x12, - 0x2e, 0x0a, 0x10, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, - 0x6f, 0x75, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x0f, 0x73, 0x63, 0x68, - 0x65, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x88, 0x01, 0x01, 0x12, - 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x0e, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x44, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x49, - 0x0a, 0x0d, 0x73, 0x6c, 0x6f, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, - 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x70, 0x74, 0x73, 0x2e, 0x53, 0x6c, 0x6f, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c, 0x73, 0x6c, 0x6f, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x1a, 0x58, 0x0a, 0x11, 0x57, 0x6f, 0x72, - 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, - 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, - 0x12, 0x2d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, - 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, - 0x02, 0x38, 0x01, 0x1a, 0x3f, 0x0a, 0x11, 0x53, 0x6c, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x3a, 0x02, 0x38, 0x01, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, - 0x5f, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x62, 0x61, 0x63, 0x6b, - 0x6f, 0x66, 0x66, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x42, - 0x0d, 0x0a, 0x0b, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x13, - 0x0a, 0x11, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, - 0x6f, 0x75, 0x74, 0x22, 0xb8, 0x02, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, - 0x73, 0x6b, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x19, 0x0a, - 0x05, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x05, - 0x75, 0x6e, 0x69, 0x74, 0x73, 0x88, 0x01, 0x01, 0x12, 0x1e, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, - 0x65, 0x78, 0x70, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x07, 0x6b, 0x65, - 0x79, 0x45, 0x78, 0x70, 0x72, 0x88, 0x01, 0x01, 0x12, 0x22, 0x0a, 0x0a, 0x75, 0x6e, 0x69, 0x74, - 0x73, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x09, - 0x75, 0x6e, 0x69, 0x74, 0x73, 0x45, 0x78, 0x70, 0x72, 0x88, 0x01, 0x01, 0x12, 0x2f, 0x0a, 0x11, - 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x5f, 0x65, 0x78, 0x70, - 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x0f, 0x6c, 0x69, 0x6d, 0x69, 0x74, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x45, 0x78, 0x70, 0x72, 0x88, 0x01, 0x01, 0x12, 0x36, 0x0a, - 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x15, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x44, 0x75, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x04, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x42, - 0x0b, 0x0a, 0x09, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x42, 0x0d, 0x0a, 0x0b, - 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x42, 0x14, 0x0a, 0x12, 0x5f, - 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x5f, 0x65, 0x78, 0x70, - 0x72, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x50, - 0x0a, 0x1d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, - 0x1f, 0x0a, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x64, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64, - 0x22, 0x37, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x52, 0x75, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x65, - 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, - 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x22, 0xe4, 0x01, 0x0a, 0x0d, 0x54, 0x61, - 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x65, - 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x06, - 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x76, - 0x31, 0x2e, 0x52, 0x75, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x12, 0x19, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x1b, - 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, - 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, 0x0b, 0x72, - 0x65, 0x61, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x72, 0x65, 0x61, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, - 0x69, 0x73, 0x5f, 0x65, 0x76, 0x69, 0x63, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x09, 0x69, 0x73, 0x45, 0x76, 0x69, 0x63, 0x74, 0x65, 0x64, 0x42, 0x08, 0x0a, 0x06, 0x5f, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, - 0x22, 0xce, 0x02, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x52, 0x75, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, - 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, - 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, - 0x12, 0x25, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x0d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x75, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x44, 0x0a, 0x09, 0x74, 0x61, 0x73, 0x6b, 0x5f, - 0x72, 0x75, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x76, 0x31, 0x2e, - 0x47, 0x65, 0x74, 0x52, 0x75, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x52, 0x08, 0x74, 0x61, 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x73, 0x12, 0x12, 0x0a, - 0x04, 0x64, 0x6f, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x64, 0x6f, 0x6e, - 0x65, 0x12, 0x2f, 0x0a, 0x13, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, - 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, - 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x65, 0x76, 0x69, 0x63, 0x74, 0x65, 0x64, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x45, 0x76, 0x69, 0x63, 0x74, 0x65, - 0x64, 0x1a, 0x4e, 0x0a, 0x0d, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x6b, 0x65, 0x79, 0x12, 0x27, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x75, 0x6e, - 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, - 0x01, 0x2a, 0x24, 0x0a, 0x0e, 0x53, 0x74, 0x69, 0x63, 0x6b, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, - 0x65, 0x67, 0x79, 0x12, 0x08, 0x0a, 0x04, 0x53, 0x4f, 0x46, 0x54, 0x10, 0x00, 0x12, 0x08, 0x0a, - 0x04, 0x48, 0x41, 0x52, 0x44, 0x10, 0x01, 0x2a, 0x5d, 0x0a, 0x11, 0x52, 0x61, 0x74, 0x65, 0x4c, - 0x69, 0x6d, 0x69, 0x74, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0a, 0x0a, 0x06, - 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x49, 0x4e, 0x55, - 0x54, 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x4f, 0x55, 0x52, 0x10, 0x02, 0x12, 0x07, - 0x0a, 0x03, 0x44, 0x41, 0x59, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x45, 0x45, 0x4b, 0x10, - 0x04, 0x12, 0x09, 0x0a, 0x05, 0x4d, 0x4f, 0x4e, 0x54, 0x48, 0x10, 0x05, 0x12, 0x08, 0x0a, 0x04, - 0x59, 0x45, 0x41, 0x52, 0x10, 0x06, 0x2a, 0x5b, 0x0a, 0x09, 0x52, 0x75, 0x6e, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x12, 0x0a, 0x0a, 0x06, 0x51, 0x55, 0x45, 0x55, 0x45, 0x44, 0x10, 0x00, 0x12, - 0x0b, 0x0a, 0x07, 0x52, 0x55, 0x4e, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, - 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x46, - 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x41, 0x4e, 0x43, 0x45, - 0x4c, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x12, 0x0b, 0x0a, 0x07, 0x45, 0x56, 0x49, 0x43, 0x54, 0x45, - 0x44, 0x10, 0x05, 0x2a, 0x7f, 0x0a, 0x18, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, - 0x63, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, - 0x16, 0x0a, 0x12, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x5f, 0x49, 0x4e, 0x5f, 0x50, 0x52, 0x4f, - 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x52, 0x4f, 0x50, 0x5f, - 0x4e, 0x45, 0x57, 0x45, 0x53, 0x54, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x51, 0x55, 0x45, 0x55, - 0x45, 0x5f, 0x4e, 0x45, 0x57, 0x45, 0x53, 0x54, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x47, 0x52, - 0x4f, 0x55, 0x50, 0x5f, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x52, 0x4f, 0x42, 0x49, 0x4e, 0x10, - 0x03, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x5f, 0x4e, 0x45, 0x57, 0x45, - 0x53, 0x54, 0x10, 0x04, 0x32, 0xcf, 0x03, 0x0a, 0x0c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x52, 0x0a, 0x0b, 0x50, 0x75, 0x74, 0x57, 0x6f, 0x72, 0x6b, - 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x20, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x0b, 0x43, 0x61, 0x6e, - 0x63, 0x65, 0x6c, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x16, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, - 0x6e, 0x63, 0x65, 0x6c, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x54, 0x61, 0x73, 0x6b, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x0b, 0x52, 0x65, 0x70, - 0x6c, 0x61, 0x79, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x16, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, - 0x70, 0x6c, 0x61, 0x79, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x54, 0x61, 0x73, 0x6b, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x12, 0x54, 0x72, 0x69, - 0x67, 0x67, 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x12, - 0x1d, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, - 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, - 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, 0x66, - 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, - 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x52, 0x75, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, - 0x18, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x75, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, - 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x76, 0x31, 0x2e, 0x47, - 0x65, 0x74, 0x52, 0x75, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x11, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x44, 0x75, - 0x72, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x1c, 0x2e, 0x76, 0x31, 0x2e, 0x42, + 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x26, 0x0a, 0x0c, 0x64, 0x69, 0x73, + 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x48, + 0x01, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, + 0x01, 0x1a, 0x5f, 0x0a, 0x18, 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, + 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x2d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, + 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x42, + 0x0f, 0x0a, 0x0d, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x22, 0x3d, 0x0a, 0x1a, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, 0x66, + 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, + 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x22, + 0x7a, 0x0a, 0x18, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x44, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, + 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x74, + 0x61, 0x73, 0x6b, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, 0x61, 0x73, 0x6b, 0x45, 0x78, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x1b, + 0x0a, 0x09, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x08, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x49, 0x64, 0x22, 0x7b, 0x0a, 0x19, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x44, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x72, 0x61, - 0x6e, 0x63, 0x68, 0x44, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x42, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x2d, 0x64, 0x65, 0x76, - 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, - 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x61, 0x73, 0x6b, + 0x5f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0e, 0x74, 0x61, 0x73, 0x6b, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x62, + 0x72, 0x61, 0x6e, 0x63, 0x68, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, + 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x49, 0x64, 0x22, 0xdd, 0x05, 0x0a, 0x1c, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x5f, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x73, + 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x72, 0x6f, 0x6e, 0x5f, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, + 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x72, 0x6f, 0x6e, 0x54, 0x72, 0x69, + 0x67, 0x67, 0x65, 0x72, 0x73, 0x12, 0x28, 0x0a, 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x06, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x70, 0x74, 0x73, 0x52, 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x12, + 0x31, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, + 0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, + 0x63, 0x79, 0x12, 0x22, 0x0a, 0x0a, 0x63, 0x72, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x63, 0x72, 0x6f, 0x6e, 0x49, 0x6e, + 0x70, 0x75, 0x74, 0x88, 0x01, 0x01, 0x12, 0x3f, 0x0a, 0x0f, 0x6f, 0x6e, 0x5f, 0x66, 0x61, 0x69, + 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x4f, + 0x70, 0x74, 0x73, 0x48, 0x01, 0x52, 0x0d, 0x6f, 0x6e, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, + 0x54, 0x61, 0x73, 0x6b, 0x88, 0x01, 0x01, 0x12, 0x2f, 0x0a, 0x06, 0x73, 0x74, 0x69, 0x63, 0x6b, + 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x69, + 0x63, 0x6b, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x48, 0x02, 0x52, 0x06, 0x73, + 0x74, 0x69, 0x63, 0x6b, 0x79, 0x88, 0x01, 0x01, 0x12, 0x2e, 0x0a, 0x10, 0x64, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x0b, 0x20, 0x01, + 0x28, 0x05, 0x48, 0x03, 0x52, 0x0f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x72, 0x69, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x88, 0x01, 0x01, 0x12, 0x38, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x63, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x61, 0x72, 0x72, 0x18, 0x0c, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, + 0x63, 0x79, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x41, + 0x72, 0x72, 0x12, 0x3a, 0x0a, 0x0f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x66, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x76, 0x31, + 0x2e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x0e, + 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x12, 0x2f, + 0x0a, 0x11, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x5f, 0x73, 0x63, 0x68, + 0x65, 0x6d, 0x61, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x04, 0x52, 0x0f, 0x69, 0x6e, 0x70, + 0x75, 0x74, 0x4a, 0x73, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x88, 0x01, 0x01, 0x42, + 0x0d, 0x0a, 0x0b, 0x5f, 0x63, 0x72, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x42, 0x12, + 0x0a, 0x10, 0x5f, 0x6f, 0x6e, 0x5f, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x74, 0x61, + 0x73, 0x6b, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x79, 0x42, 0x13, 0x0a, + 0x11, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x6a, 0x73, 0x6f, + 0x6e, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x22, 0x70, 0x0a, 0x0d, 0x44, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x78, 0x70, + 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, + 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x6f, + 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, + 0x1d, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, + 0x48, 0x00, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x88, 0x01, 0x01, 0x42, 0x0a, + 0x0a, 0x08, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0xb7, 0x01, 0x0a, 0x0b, 0x43, + 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x78, + 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x08, 0x6d, 0x61, + 0x78, 0x5f, 0x72, 0x75, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x07, + 0x6d, 0x61, 0x78, 0x52, 0x75, 0x6e, 0x73, 0x88, 0x01, 0x01, 0x12, 0x48, 0x0a, 0x0e, 0x6c, 0x69, + 0x6d, 0x69, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, + 0x6e, 0x63, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, + 0x48, 0x01, 0x52, 0x0d, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, + 0x79, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x75, 0x6e, + 0x73, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x61, + 0x74, 0x65, 0x67, 0x79, 0x22, 0x85, 0x07, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, + 0x61, 0x73, 0x6b, 0x4f, 0x70, 0x74, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x61, 0x64, 0x61, + 0x62, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, + 0x61, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x6e, + 0x70, 0x75, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, + 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x72, + 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x0b, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x6c, + 0x69, 0x6d, 0x69, 0x74, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x76, 0x31, + 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x61, 0x74, 0x65, 0x4c, + 0x69, 0x6d, 0x69, 0x74, 0x52, 0x0a, 0x72, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, + 0x12, 0x49, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, + 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x70, 0x74, 0x73, 0x2e, 0x57, 0x6f, 0x72, 0x6b, + 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c, 0x77, + 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x2a, 0x0a, 0x0e, 0x62, + 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x5f, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x02, 0x48, 0x00, 0x52, 0x0d, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x46, 0x61, + 0x63, 0x74, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x33, 0x0a, 0x13, 0x62, 0x61, 0x63, 0x6b, 0x6f, + 0x66, 0x66, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x05, 0x48, 0x01, 0x52, 0x11, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x4d, + 0x61, 0x78, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x88, 0x01, 0x01, 0x12, 0x31, 0x0a, 0x0b, + 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x0b, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, + 0x63, 0x79, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, + 0x37, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0c, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x43, 0x6f, 0x6e, + 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x48, 0x02, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x88, 0x01, 0x01, 0x12, 0x2e, 0x0a, 0x10, 0x73, 0x63, 0x68, 0x65, + 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x0d, 0x20, 0x01, + 0x28, 0x09, 0x48, 0x03, 0x52, 0x0f, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x69, + 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x64, + 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, + 0x44, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x49, 0x0a, 0x0d, 0x73, 0x6c, 0x6f, 0x74, 0x5f, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x70, + 0x74, 0x73, 0x2e, 0x53, 0x6c, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c, 0x73, 0x6c, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x73, 0x1a, 0x58, 0x0a, 0x11, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, + 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2d, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, + 0x73, 0x69, 0x72, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3f, 0x0a, 0x11, + 0x53, 0x6c, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x11, 0x0a, + 0x0f, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x5f, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, + 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x5f, 0x6d, 0x61, 0x78, + 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x63, 0x6f, 0x6e, + 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x73, 0x63, 0x68, 0x65, + 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0xb8, 0x02, 0x0a, + 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x61, 0x74, 0x65, 0x4c, + 0x69, 0x6d, 0x69, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x19, 0x0a, 0x05, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x05, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x88, 0x01, + 0x01, 0x12, 0x1e, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x45, 0x78, 0x70, 0x72, 0x88, 0x01, + 0x01, 0x12, 0x22, 0x0a, 0x0a, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x09, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x45, 0x78, + 0x70, 0x72, 0x88, 0x01, 0x01, 0x12, 0x2f, 0x0a, 0x11, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x73, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x48, 0x03, 0x52, 0x0f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x45, + 0x78, 0x70, 0x72, 0x88, 0x01, 0x01, 0x12, 0x36, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x61, + 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, + 0x04, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x08, + 0x0a, 0x06, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x6b, 0x65, 0x79, + 0x5f, 0x65, 0x78, 0x70, 0x72, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x5f, + 0x65, 0x78, 0x70, 0x72, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x73, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x64, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x50, 0x0a, 0x1d, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x77, 0x6f, 0x72, 0x6b, + 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77, + 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64, 0x22, 0x37, 0x0a, 0x14, 0x47, 0x65, 0x74, + 0x52, 0x75, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x49, 0x64, 0x22, 0xe4, 0x01, 0x0a, 0x0d, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x44, 0x65, + 0x74, 0x61, 0x69, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x75, 0x6e, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x19, 0x0a, 0x05, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, + 0x74, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x61, 0x64, 0x61, 0x62, 0x6c, 0x65, + 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x61, 0x64, 0x61, + 0x62, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x65, 0x76, 0x69, 0x63, + 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x45, 0x76, 0x69, + 0x63, 0x74, 0x65, 0x64, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, 0x09, + 0x0a, 0x07, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0xce, 0x02, 0x0a, 0x15, 0x47, 0x65, + 0x74, 0x52, 0x75, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x25, 0x0a, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x76, 0x31, 0x2e, 0x52, + 0x75, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x12, 0x44, 0x0a, 0x09, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x72, 0x75, 0x6e, 0x73, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x75, 0x6e, 0x44, + 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x54, + 0x61, 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x74, 0x61, + 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x6f, 0x6e, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x64, 0x6f, 0x6e, 0x65, 0x12, 0x2f, 0x0a, 0x13, 0x61, 0x64, + 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x61, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x69, + 0x73, 0x5f, 0x65, 0x76, 0x69, 0x63, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x09, 0x69, 0x73, 0x45, 0x76, 0x69, 0x63, 0x74, 0x65, 0x64, 0x1a, 0x4e, 0x0a, 0x0d, 0x54, 0x61, + 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x27, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x76, + 0x31, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x2a, 0x24, 0x0a, 0x0e, 0x53, 0x74, + 0x69, 0x63, 0x6b, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x08, 0x0a, 0x04, + 0x53, 0x4f, 0x46, 0x54, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x41, 0x52, 0x44, 0x10, 0x01, + 0x2a, 0x5d, 0x0a, 0x11, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x44, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x10, + 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x49, 0x4e, 0x55, 0x54, 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, + 0x04, 0x48, 0x4f, 0x55, 0x52, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x44, 0x41, 0x59, 0x10, 0x03, + 0x12, 0x08, 0x0a, 0x04, 0x57, 0x45, 0x45, 0x4b, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x4d, 0x4f, + 0x4e, 0x54, 0x48, 0x10, 0x05, 0x12, 0x08, 0x0a, 0x04, 0x59, 0x45, 0x41, 0x52, 0x10, 0x06, 0x2a, + 0x5b, 0x0a, 0x09, 0x52, 0x75, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0a, 0x0a, 0x06, + 0x51, 0x55, 0x45, 0x55, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x55, 0x4e, 0x4e, + 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, + 0x45, 0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x03, + 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x12, + 0x0b, 0x0a, 0x07, 0x45, 0x56, 0x49, 0x43, 0x54, 0x45, 0x44, 0x10, 0x05, 0x2a, 0x7f, 0x0a, 0x18, + 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, + 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x41, 0x4e, 0x43, + 0x45, 0x4c, 0x5f, 0x49, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x00, + 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x52, 0x4f, 0x50, 0x5f, 0x4e, 0x45, 0x57, 0x45, 0x53, 0x54, 0x10, + 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x51, 0x55, 0x45, 0x55, 0x45, 0x5f, 0x4e, 0x45, 0x57, 0x45, 0x53, + 0x54, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x5f, 0x52, 0x4f, 0x55, + 0x4e, 0x44, 0x5f, 0x52, 0x4f, 0x42, 0x49, 0x4e, 0x10, 0x03, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x41, + 0x4e, 0x43, 0x45, 0x4c, 0x5f, 0x4e, 0x45, 0x57, 0x45, 0x53, 0x54, 0x10, 0x04, 0x32, 0xcf, 0x03, + 0x0a, 0x0c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x52, + 0x0a, 0x0b, 0x50, 0x75, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x20, 0x2e, + 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, + 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x21, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, + 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x0b, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x54, 0x61, 0x73, 0x6b, + 0x73, 0x12, 0x16, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x54, 0x61, 0x73, + 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x43, + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x0b, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x54, 0x61, 0x73, 0x6b, + 0x73, 0x12, 0x16, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x54, 0x61, 0x73, + 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x52, + 0x65, 0x70, 0x6c, 0x61, 0x79, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x53, 0x0a, 0x12, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x57, 0x6f, 0x72, + 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x12, 0x1d, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, + 0x69, 0x67, 0x67, 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x69, + 0x67, 0x67, 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x52, 0x75, + 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x18, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, + 0x74, 0x52, 0x75, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x75, 0x6e, 0x44, 0x65, + 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, + 0x11, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x44, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x61, + 0x73, 0x6b, 0x12, 0x1c, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x44, 0x75, + 0x72, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1d, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x44, 0x75, 0x72, 0x61, + 0x62, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, + 0x42, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, + 0x74, 0x63, 0x68, 0x65, 0x74, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65, + 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/internal/services/shared/proto/v1/workflows_grpc.pb.go b/internal/services/shared/proto/v1/workflows_grpc.pb.go index 96a3b1b664..d80484785e 100644 --- a/internal/services/shared/proto/v1/workflows_grpc.pb.go +++ b/internal/services/shared/proto/v1/workflows_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 -// - protoc v5.29.3 +// - protoc v7.35.1 // source: v1/workflows.proto package v1 diff --git a/pkg/client/admin.go b/pkg/client/admin.go index 20c9edcb17..c18792dedb 100644 --- a/pkg/client/admin.go +++ b/pkg/client/admin.go @@ -34,6 +34,7 @@ type ChildWorkflowOpts struct { AdditionalMetadata *map[string]string Priority *int32 DesiredWorkerLabels map[string]*types.DesiredWorkerLabel + DisplayName *string } // NewChildWorkflowTriggerRequest builds the trigger request used to start a child workflow. @@ -81,6 +82,12 @@ func NewChildWorkflowTriggerRequest(workflowName string, input interface{}, opts } } + if opts.DisplayName != nil { + if err := WithDisplayName(*opts.DisplayName)(request); err != nil { + return nil, fmt.Errorf("could not apply display name: %w", err) + } + } + return request, nil } @@ -346,6 +353,16 @@ func WithPriority(priority int32) RunOptFunc { } } +// WithDisplayName sets a custom display name for the run. The engine trims and +// truncates it; an empty/whitespace value falls back to the generated name. +func WithDisplayName(name string) RunOptFunc { + return func(r *v1contracts.TriggerWorkflowRequest) error { + r.DisplayName = &name + + return nil + } +} + func WithDesiredWorkerLabels(labels map[string]*types.DesiredWorkerLabel) RunOptFunc { return func(r *admincontracts.TriggerWorkflowRequest) error { r.DesiredWorkerLabels = desiredWorkerLabelsToProto(labels) diff --git a/pkg/client/admin_display_name_test.go b/pkg/client/admin_display_name_test.go new file mode 100644 index 0000000000..e70f8b0c10 --- /dev/null +++ b/pkg/client/admin_display_name_test.go @@ -0,0 +1,37 @@ +package client + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + v1contracts "github.com/hatchet-dev/hatchet/internal/services/shared/proto/v1" +) + +func TestWithDisplayName_setsRequestField(t *testing.T) { + req := &v1contracts.TriggerWorkflowRequest{Name: "wf"} + + err := WithDisplayName("Acme Corp")(req) + require.NoError(t, err) + + require.NotNil(t, req.DisplayName) + assert.Equal(t, "Acme Corp", *req.DisplayName) +} + +func TestNewChildWorkflowTriggerRequest_setsDisplayName(t *testing.T) { + name := "Acme Corp" + + req, err := NewChildWorkflowTriggerRequest("child-wf", map[string]any{}, &ChildWorkflowOpts{DisplayName: &name}, nil) + require.NoError(t, err) + + require.NotNil(t, req.DisplayName) + assert.Equal(t, "Acme Corp", *req.DisplayName, "child spawn carries the display name onto the request") +} + +func TestNewChildWorkflowTriggerRequest_omitsDisplayName(t *testing.T) { + req, err := NewChildWorkflowTriggerRequest("child-wf", map[string]any{}, &ChildWorkflowOpts{}, nil) + require.NoError(t, err) + + assert.Nil(t, req.DisplayName, "an unset display name leaves the request field nil") +} diff --git a/pkg/client/rest/gen.go b/pkg/client/rest/gen.go index a57e737c53..364b4ab9bc 100644 --- a/pkg/client/rest/gen.go +++ b/pkg/client/rest/gen.go @@ -2059,7 +2059,10 @@ type V1TaskTimingList struct { // V1TriggerWorkflowRunRequest defines model for V1TriggerWorkflowRunRequest. type V1TriggerWorkflowRunRequest struct { AdditionalMetadata *map[string]interface{} `json:"additionalMetadata,omitempty"` - Input map[string]interface{} `json:"input"` + + // DisplayName A custom display name for the run. Falls back to a generated name if unset. + DisplayName *string `json:"displayName,omitempty"` + Input map[string]interface{} `json:"input"` // Priority The priority of the workflow run. Priority *int `json:"priority,omitempty"` diff --git a/pkg/repository/durable_events_test.go b/pkg/repository/durable_events_test.go index 14d7cce814..c2c61fee06 100644 --- a/pkg/repository/durable_events_test.go +++ b/pkg/repository/durable_events_test.go @@ -13,6 +13,41 @@ import ( "github.com/stretchr/testify/assert" ) +// A durable replay re-issues the same child spawn; the child is matched by its +// idempotency key and reused with the first spawn's stored name. Because display_name +// is display-only, it must never enter the idempotency key — otherwise editing a +// cosmetic label would change the key, spawn a duplicate, and (per the key comparison +// at the sole non-determinism check) risk a NonDeterminismError. This guards that +// invariant: opts differing only in display_name hash to the same key. +func Test_createIdempotencyKey_ignores_display_name(t *testing.T) { + r := &durableEventsRepository{} + + nameA := "A" + nameB := "B" + + newOpt := func(displayName *string) *WorkflowNameTriggerOpts { + return &WorkflowNameTriggerOpts{ + TriggerTaskData: &TriggerTaskData{ + WorkflowName: "my-workflow", + Data: []byte(`{"x":1}`), + DisplayName: displayName, + }, + } + } + + keyUnset, err := r.createIdempotencyKey(sqlcv1.V1DurableEventLogKindRUN, newOpt(nil), nil) + assert.NoError(t, err) + + keyA, err := r.createIdempotencyKey(sqlcv1.V1DurableEventLogKindRUN, newOpt(&nameA), nil) + assert.NoError(t, err) + + keyB, err := r.createIdempotencyKey(sqlcv1.V1DurableEventLogKindRUN, newOpt(&nameB), nil) + assert.NoError(t, err) + + assert.Equal(t, keyUnset, keyA, "setting a display name must not change the durable idempotency key") + assert.Equal(t, keyA, keyB, "changing display name on replay must not change the key (child reused, first name wins, no NonDeterminismError)") +} + func TestStaleInvocationError_ImplementsError(t *testing.T) { id := uuid.New() err := &StaleInvocationError{ diff --git a/pkg/repository/task.go b/pkg/repository/task.go index 3e1f735da9..53c776e37f 100644 --- a/pkg/repository/task.go +++ b/pkg/repository/task.go @@ -99,6 +99,10 @@ type CreateTaskOpts struct { // (optional) the key of the event that triggered the workflow run, if there was one TriggeringEventKey *string + + // (optional) custom display name for the run. Only set for single-task (non-DAG) + // runs, where the task IS the run; DAG step tasks keep their generated names. + DisplayName *string } type ReplayTasksResult struct { @@ -1968,7 +1972,11 @@ func (r *sharedRepository) insertTasks( scheduleTimeouts[i] = stepConfig.ScheduleTimeout stepTimeouts[i] = stepConfig.Timeout.String externalIds[i] = task.ExternalId - displayNames[i] = fmt.Sprintf("%s-%d", stepConfig.ReadableId.String, unix) + if task.DisplayName != nil { + displayNames[i] = *task.DisplayName + } else { + displayNames[i] = fmt.Sprintf("%s-%d", stepConfig.ReadableId.String, unix) + } stepIndices[i] = int64(task.StepIndex) retryBackoffFactors[i] = stepConfig.RetryBackoffFactor retryMaxBackoffs[i] = stepConfig.RetryMaxBackoff diff --git a/pkg/repository/trigger.go b/pkg/repository/trigger.go index 9de04e15ed..e7471890c3 100644 --- a/pkg/repository/trigger.go +++ b/pkg/repository/trigger.go @@ -8,6 +8,7 @@ import ( "slices" "strings" "time" + "unicode/utf8" "github.com/google/uuid" "github.com/jackc/pgx/v5/pgtype" @@ -73,6 +74,33 @@ type TriggerTaskData struct { // (optional) overrides for desired worker labels for the task, used for routing a task to a specific worker (or worker pool) DesiredWorkerLabels []*sqlcv1.GetDesiredLabelsRow `json:"desired_worker_labels"` + + // (optional) custom display name for the run + DisplayName *string `json:"display_name"` +} + +// maxDisplayNameRunes bounds a stored run display name; over-long labels are +// truncated (never rejected) so a cosmetic label can't fail a trigger. +const maxDisplayNameRunes = 255 + +// NormalizeDisplayName normalizes a caller-supplied display name for a run. +func NormalizeDisplayName(in *string) *string { + if in == nil { + return nil + } + + trimmed := strings.TrimSpace(*in) + if trimmed == "" { + return nil + } + + // Truncate to 255 runes (not bytes) so an over-long label is stored rather + // than rejected, and a multibyte character is never split mid-rune. + if utf8.RuneCountInString(trimmed) > maxDisplayNameRunes { + trimmed = string([]rune(trimmed)[:maxDisplayNameRunes]) + } + + return &trimmed } func ProtoToDesiredWorkerLabel(key string, strValue *string, intValue *int32, required *bool, weight *int32, comparator *string) *sqlcv1.GetDesiredLabelsRow { @@ -134,6 +162,9 @@ type createDAGOpts struct { // (optional) overrides for desired worker labels, propagated to all downstream tasks DesiredWorkerLabels []*sqlcv1.GetDesiredLabelsRow + + // (optional) custom display name for the DAG run + DisplayName *string } type TriggerRepository interface { @@ -588,6 +619,7 @@ type triggerTuple struct { desiredWorkerLabels []*sqlcv1.GetDesiredLabelsRow triggeringEventExternalId *uuid.UUID triggeringEventKey *string + displayName *string } type createCoreUserEventOpts struct { @@ -1038,6 +1070,9 @@ func (r *sharedRepository) triggerWorkflows( if isDag { dagTaskOpts[tuple.externalId] = append(dagTaskOpts[tuple.externalId], opt) } else { + // single-task run: the task IS the run, so it carries the display name. + // DAG step tasks keep their generated names (the DAG row is named instead). + opt.DisplayName = tuple.displayName nonDagTaskOpts = append(nonDagTaskOpts, opt) } } @@ -1166,6 +1201,7 @@ func (r *sharedRepository) triggerWorkflows( AdditionalMetadata: tuple.additionalMetadata, ParentTaskExternalID: tuple.parentExternalId, DesiredWorkerLabels: tuple.desiredWorkerLabels, + DisplayName: tuple.displayName, }) } } @@ -1411,7 +1447,11 @@ func (r *sharedRepository) createDAGs(ctx context.Context, tx sqlcv1.DBTX, tenan for _, opt := range opts { tenantIds = append(tenantIds, tenantId) externalIds = append(externalIds, opt.ExternalId) - displayNames = append(displayNames, fmt.Sprintf("%s-%d", opt.WorkflowName, unix)) + if opt.DisplayName != nil { + displayNames = append(displayNames, *opt.DisplayName) + } else { + displayNames = append(displayNames, fmt.Sprintf("%s-%d", opt.WorkflowName, unix)) + } workflowIds = append(workflowIds, opt.WorkflowId) workflowVersionIds = append(workflowVersionIds, opt.WorkflowVersionId) @@ -2363,6 +2403,7 @@ func (r *sharedRepository) prepareTriggerFromWorkflowNames(ctx context.Context, childKey: opt.ChildKey, priority: opt.Priority, desiredWorkerLabels: opt.DesiredWorkerLabels, + displayName: opt.DisplayName, }) } } @@ -2418,6 +2459,7 @@ func (r *sharedRepository) NewTriggerTaskData( AdditionalMetadata: []byte(additionalMeta), DesiredWorkerId: desiredWorkerId, Priority: req.Priority, + DisplayName: NormalizeDisplayName(req.DisplayName), } if len(req.DesiredWorkerLabels) > 0 { diff --git a/pkg/repository/trigger_display_name_integration_test.go b/pkg/repository/trigger_display_name_integration_test.go new file mode 100644 index 0000000000..ec18517b72 --- /dev/null +++ b/pkg/repository/trigger_display_name_integration_test.go @@ -0,0 +1,364 @@ +//go:build integration + +package repository_test + +import ( + "context" + "fmt" + "strings" + "testing" + "time" + "unicode/utf8" + + "github.com/google/uuid" + "github.com/stretchr/testify/require" + + v1contracts "github.com/hatchet-dev/hatchet/internal/services/shared/proto/v1" + "github.com/hatchet-dev/hatchet/internal/testutils" + "github.com/hatchet-dev/hatchet/pkg/config/database" + repo "github.com/hatchet-dev/hatchet/pkg/repository" + "github.com/hatchet-dev/hatchet/pkg/repository/sqlcv1" +) + +func runTriggerTest(t *testing.T, test func(conf *database.Layer) error) { + t.Helper() + // `internal/testutils.Prepare` constructs a server config and requires a RabbitMQ URL. + t.Setenv("SERVER_MSGQUEUE_RABBITMQ_URL", "amqp://user:password@localhost:5672/") + testutils.RunTestWithDatabase(t, test) +} + +// createTriggerTenant creates a fresh tenant so each test's rows are isolated. +func createTriggerTenant(t *testing.T, ctx context.Context, r repo.Repository, name string) uuid.UUID { + t.Helper() + + tenantId := uuid.New() + _, err := r.Tenant().CreateTenant(ctx, &repo.CreateTenantOpts{ + ID: &tenantId, + Name: name, + Slug: fmt.Sprintf("%s-%s", name, tenantId.String()), + }) + require.NoError(t, err) + + return tenantId +} + +// putSingleTaskWorkflow registers a single-task (non-DAG) workflow and returns its name. +func putSingleTaskWorkflow(t *testing.T, ctx context.Context, r repo.Repository, tenantId uuid.UUID, name string) string { + t.Helper() + + desc := "display-name test workflow" + _, err := r.Workflows().PutWorkflowVersion(ctx, tenantId, &repo.CreateWorkflowVersionOpts{ + Name: name, + Description: &desc, + Tasks: []repo.CreateStepOpts{ + {ReadableId: "single-step", Action: "test:run"}, + }, + }) + require.NoError(t, err) + + return name +} + +// putDagWorkflow registers a multi-step (DAG) workflow: step-two depends on step-one. +func putDagWorkflow(t *testing.T, ctx context.Context, r repo.Repository, tenantId uuid.UUID, name string) string { + t.Helper() + + desc := "display-name DAG test workflow" + _, err := r.Workflows().PutWorkflowVersion(ctx, tenantId, &repo.CreateWorkflowVersionOpts{ + Name: name, + Description: &desc, + Tasks: []repo.CreateStepOpts{ + {ReadableId: "step-one", Action: "test:run"}, + {ReadableId: "step-two", Action: "test:run", Parents: []string{"step-one"}}, + }, + }) + require.NoError(t, err) + + return name +} + +// triggerRun drives the real trigger path (NewTriggerTaskData -> PopulateExternalIds -> +// TriggerFromWorkflowNames) with the given display name and returns the created rows. +func triggerRun( + t *testing.T, + ctx context.Context, + r repo.Repository, + tenantId uuid.UUID, + workflowName string, + displayName *string, +) ([]*repo.V1TaskWithPayload, []*repo.DAGWithData) { + t.Helper() + + req := &v1contracts.TriggerWorkflowRequest{ + Name: workflowName, + Input: "{}", + DisplayName: displayName, + } + + ttd, err := r.Triggers().NewTriggerTaskData(ctx, tenantId, req, nil) + require.NoError(t, err) + + opts := []*repo.WorkflowNameTriggerOpts{{TriggerTaskData: ttd}} + + err = r.Triggers().PopulateExternalIdsForWorkflow(ctx, tenantId, opts) + require.NoError(t, err) + + tasks, dags, err := r.Triggers().TriggerFromWorkflowNames(ctx, tenantId, opts) + require.NoError(t, err) + + return tasks, dags +} + +// triggerRunMany drives one TriggerFromWorkflowNames call carrying a per-item display +// name for each element, mirroring run_many / bulk trigger. Returns the created tasks. +func triggerRunMany( + t *testing.T, + ctx context.Context, + r repo.Repository, + tenantId uuid.UUID, + workflowName string, + displayNames []*string, +) []*repo.V1TaskWithPayload { + t.Helper() + + opts := make([]*repo.WorkflowNameTriggerOpts, 0, len(displayNames)) + for _, dn := range displayNames { + req := &v1contracts.TriggerWorkflowRequest{ + Name: workflowName, + Input: "{}", + DisplayName: dn, + } + ttd, err := r.Triggers().NewTriggerTaskData(ctx, tenantId, req, nil) + require.NoError(t, err) + opts = append(opts, &repo.WorkflowNameTriggerOpts{TriggerTaskData: ttd}) + } + + err := r.Triggers().PopulateExternalIdsForWorkflow(ctx, tenantId, opts) + require.NoError(t, err) + + tasks, _, err := r.Triggers().TriggerFromWorkflowNames(ctx, tenantId, opts) + require.NoError(t, err) + + return tasks +} + +func strPtr(s string) *string { return &s } + +func int32Ptr(i int32) *int32 { return &i } + +// spawnChildOnce runs one non-durable child spawn round: build the trigger data with the +// parent + child index, populate external ids (which dedups on the child spawn key), and +// trigger only if the opt was not deduped. Returns the (mutated) opt and any created tasks. +func spawnChildOnce( + t *testing.T, + ctx context.Context, + r repo.Repository, + tenantId uuid.UUID, + childWorkflowName string, + parent *sqlcv1.FlattenExternalIdsRow, + childIndex int32, + displayName *string, +) (*repo.WorkflowNameTriggerOpts, []*repo.V1TaskWithPayload) { + t.Helper() + + req := &v1contracts.TriggerWorkflowRequest{ + Name: childWorkflowName, + Input: "{}", + DisplayName: displayName, + ChildIndex: int32Ptr(childIndex), + } + + ttd, err := r.Triggers().NewTriggerTaskData(ctx, tenantId, req, parent) + require.NoError(t, err) + + opt := &repo.WorkflowNameTriggerOpts{TriggerTaskData: ttd} + opts := []*repo.WorkflowNameTriggerOpts{opt} + + err = r.Triggers().PopulateExternalIdsForWorkflow(ctx, tenantId, opts) + require.NoError(t, err) + + if opt.ShouldSkip { + return opt, nil + } + + tasks, _, err := r.Triggers().TriggerFromWorkflowNames(ctx, tenantId, opts) + require.NoError(t, err) + + return opt, tasks +} + +func TestTriggerDisplayName_KeepsFirstNameOnChildReTrigger(t *testing.T) { + runTriggerTest(t, func(conf *database.Layer) error { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + r := conf.V1 + tenantId := createTriggerTenant(t, ctx, r, "dn-child") + + // A real parent run to spawn children from. + parentWf := putSingleTaskWorkflow(t, ctx, r, tenantId, "dn-child-parent") + parentTasks, _ := triggerRun(t, ctx, r, tenantId, parentWf, strPtr("Parent")) + require.Len(t, parentTasks, 1) + parent := parentTasks[0] + + parentRow := &sqlcv1.FlattenExternalIdsRow{ + ID: parent.ID, + InsertedAt: parent.InsertedAt, + ExternalID: parent.ExternalID, + WorkflowRunID: parent.WorkflowRunID, + } + + childWf := putSingleTaskWorkflow(t, ctx, r, tenantId, "dn-child-wf") + + // First spawn: child index 0, display name "A" -> creates the child run. + firstOpt, firstTasks := spawnChildOnce(t, ctx, r, tenantId, childWf, parentRow, 0, strPtr("A")) + require.False(t, firstOpt.ShouldSkip, "first spawn is not deduped") + require.Len(t, firstTasks, 1) + require.Equal(t, "A", firstTasks[0].DisplayName) + firstChildId := firstOpt.ExternalId + + // Second spawn: SAME (parent, childIndex, childKey) but display name "B". + secondOpt, secondTasks := spawnChildOnce(t, ctx, r, tenantId, childWf, parentRow, 0, strPtr("B")) + require.True(t, secondOpt.ShouldSkip, + "re-trigger with same (parent, childIndex, childKey) is deduped; display name is not part of the key") + require.Equal(t, firstChildId, secondOpt.ExternalId, "reuses the first child's external id") + require.Nil(t, secondTasks, "no new run is created on re-trigger") + + // The existing child run keeps its original name "A" (never rewritten to "B"). + var storedName string + err := conf.Pool.QueryRow(ctx, + `SELECT display_name FROM v1_task WHERE tenant_id = $1 AND external_id = $2`, + tenantId, firstChildId, + ).Scan(&storedName) + require.NoError(t, err) + require.Equal(t, "A", storedName, "first display name wins on re-trigger") + + return nil + }) +} + +func TestTriggerDisplayName_NamesSingleTaskRun(t *testing.T) { + runTriggerTest(t, func(conf *database.Layer) error { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + r := conf.V1 + tenantId := createTriggerTenant(t, ctx, r, "dn-single") + workflowName := putSingleTaskWorkflow(t, ctx, r, tenantId, "dn-single-wf") + + tasks, dags := triggerRun(t, ctx, r, tenantId, workflowName, strPtr("Acme Corp")) + + require.Len(t, dags, 0, "single-task workflow creates no DAG") + require.Len(t, tasks, 1) + require.Equal(t, "Acme Corp", tasks[0].DisplayName, "the task IS the run, so it carries the display name") + + return nil + }) +} + +func TestTriggerDisplayName_NamesDagRunNotSteps(t *testing.T) { + runTriggerTest(t, func(conf *database.Layer) error { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + r := conf.V1 + tenantId := createTriggerTenant(t, ctx, r, "dn-dag") + workflowName := putDagWorkflow(t, ctx, r, tenantId, "dn-dag-wf") + + tasks, dags := triggerRun(t, ctx, r, tenantId, workflowName, strPtr("Acme Corp")) + + require.Len(t, dags, 1, "multi-step workflow creates a DAG") + require.Equal(t, "Acme Corp", dags[0].DisplayName, "the DAG row carries the display name") + + for _, task := range tasks { + require.Regexp(t, `^step-(one|two)-\d+$`, task.DisplayName, + "DAG step tasks keep their generated - names") + } + + return nil + }) +} + +func TestTriggerDisplayName_FallsBackWhenNil(t *testing.T) { + runTriggerTest(t, func(conf *database.Layer) error { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + r := conf.V1 + tenantId := createTriggerTenant(t, ctx, r, "dn-nil") + workflowName := putSingleTaskWorkflow(t, ctx, r, tenantId, "dn-nil-wf") + + tasks, _ := triggerRun(t, ctx, r, tenantId, workflowName, nil) + + require.Len(t, tasks, 1) + require.Regexp(t, `^single-step-\d+$`, tasks[0].DisplayName, + "omitting display name preserves the generated - label") + + return nil + }) +} + +func TestTriggerDisplayName_TreatsWhitespaceAsUnset(t *testing.T) { + runTriggerTest(t, func(conf *database.Layer) error { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + r := conf.V1 + tenantId := createTriggerTenant(t, ctx, r, "dn-ws") + workflowName := putSingleTaskWorkflow(t, ctx, r, tenantId, "dn-ws-wf") + + tasks, _ := triggerRun(t, ctx, r, tenantId, workflowName, strPtr(" ")) + + require.Len(t, tasks, 1) + require.Regexp(t, `^single-step-\d+$`, tasks[0].DisplayName, + "whitespace-only display name is treated as unset") + + return nil + }) +} + +func TestTriggerDisplayName_TruncatesTo255Runes(t *testing.T) { + runTriggerTest(t, func(conf *database.Layer) error { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + r := conf.V1 + tenantId := createTriggerTenant(t, ctx, r, "dn-trunc") + workflowName := putSingleTaskWorkflow(t, ctx, r, tenantId, "dn-trunc-wf") + + // "世" is a 3-byte rune; 300 of them would split mid-rune under byte truncation. + long := strings.Repeat("世", 300) + tasks, _ := triggerRun(t, ctx, r, tenantId, workflowName, strPtr(long)) + + require.Len(t, tasks, 1) + require.Equal(t, 255, utf8.RuneCountInString(tasks[0].DisplayName), + "stored display name is truncated to 255 runes") + require.True(t, utf8.ValidString(tasks[0].DisplayName), "no multibyte rune was split") + + return nil + }) +} + +func TestTriggerDisplayName_DistinctNamePerRunMany(t *testing.T) { + runTriggerTest(t, func(conf *database.Layer) error { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + r := conf.V1 + tenantId := createTriggerTenant(t, ctx, r, "dn-many") + workflowName := putSingleTaskWorkflow(t, ctx, r, tenantId, "dn-many-wf") + + tasks := triggerRunMany(t, ctx, r, tenantId, workflowName, + []*string{strPtr("Alpha"), strPtr("Bravo"), strPtr("Charlie")}) + + require.Len(t, tasks, 3) + names := map[string]bool{} + for _, task := range tasks { + names[task.DisplayName] = true + } + require.Equal(t, map[string]bool{"Alpha": true, "Bravo": true, "Charlie": true}, names, + "each run_many item carries its own display name") + + return nil + }) +} diff --git a/pkg/repository/trigger_test.go b/pkg/repository/trigger_test.go index c0294b0f70..ca076b6792 100644 --- a/pkg/repository/trigger_test.go +++ b/pkg/repository/trigger_test.go @@ -3,7 +3,9 @@ package repository import ( "encoding/hex" "encoding/json" + "strings" "testing" + "unicode/utf8" "github.com/google/uuid" "github.com/stretchr/testify/assert" @@ -43,6 +45,39 @@ func Test_cleanAdditionalMetadataTableTest(t *testing.T) { } } +func Test_NormalizeDisplayName_returns_trimmed_value(t *testing.T) { + in := "Acme Corp" + + got := NormalizeDisplayName(&in) + + require.NotNil(t, got) + assert.Equal(t, "Acme Corp", *got) +} + +func Test_NormalizeDisplayName_returns_nil_for_nil(t *testing.T) { + assert.Nil(t, NormalizeDisplayName(nil)) +} + +func Test_NormalizeDisplayName_returns_nil_for_whitespace(t *testing.T) { + empty := "" + assert.Nil(t, NormalizeDisplayName(&empty)) + + spaces := " \t\n " + assert.Nil(t, NormalizeDisplayName(&spaces)) +} + +func Test_NormalizeDisplayName_truncates_by_rune_not_byte(t *testing.T) { + // "世" is 3 bytes; 300 of them is 900 bytes. Byte-truncation would split a + // multibyte rune, so this proves the truncation is rune-safe. + in := strings.Repeat("世", 300) + + got := NormalizeDisplayName(&in) + + require.NotNil(t, got) + assert.Equal(t, 255, utf8.RuneCountInString(*got), "truncated to 255 runes") + assert.True(t, utf8.ValidString(*got), "no multibyte rune was split") +} + func Test_ensureTraceparent_creates_when_absent(t *testing.T) { wfRunID := uuid.New() meta := []byte(`{"key":"value"}`) diff --git a/pkg/worker/context.go b/pkg/worker/context.go index dace28405a..f068d6dd98 100644 --- a/pkg/worker/context.go +++ b/pkg/worker/context.go @@ -597,6 +597,7 @@ type SpawnWorkflowOpts struct { AdditionalMetadata *map[string]string Priority *int32 DesiredWorkerLabels map[string]*types.DesiredWorkerLabel + DisplayName *string } func (h *hatchetContext) saveOrLoadListener() (*client.WorkflowRunsListener, error) { @@ -675,6 +676,7 @@ func (h *hatchetContext) SpawnWorkflow(workflowName string, input any, opts *Spa AdditionalMetadata: opts.AdditionalMetadata, Priority: opts.Priority, DesiredWorkerLabels: opts.DesiredWorkerLabels, + DisplayName: opts.DisplayName, }, ) @@ -694,6 +696,7 @@ type SpawnWorkflowsOpts struct { Sticky *bool AdditionalMetadata *map[string]string DesiredWorkerLabels map[string]*types.DesiredWorkerLabel + DisplayName *string } // Deprecated: SpawnWorkflows is an internal method used by the new Go SDK. @@ -743,6 +746,7 @@ func (h *hatchetContext) SpawnWorkflows(childWorkflows []*SpawnWorkflowsOpts) ([ DesiredWorkerId: desiredWorker, AdditionalMetadata: c.AdditionalMetadata, DesiredWorkerLabels: c.DesiredWorkerLabels, + DisplayName: c.DisplayName, }, } } diff --git a/sdks/go/client.go b/sdks/go/client.go index f45b730bf3..e0302f08ef 100644 --- a/sdks/go/client.go +++ b/sdks/go/client.go @@ -946,6 +946,9 @@ func (c *Client) runWorkflowInternal(ctx context.Context, otelCtx context.Contex if runOpts.DesiredWorkerLabels != nil { v0Opts = append(v0Opts, v0Client.WithDesiredWorkerLabels(runOpts.DesiredWorkerLabels)) } + if runOpts.DisplayName != nil { + v0Opts = append(v0Opts, v0Client.WithDisplayName(*runOpts.DisplayName)) + } var v0Workflow *v0Client.Workflow var err error @@ -974,6 +977,7 @@ func (c *Client) runWorkflowInternal(ctx context.Context, otelCtx context.Contex Priority: priority, AdditionalMetadata: additionalMetadata, DesiredWorkerLabels: runOpts.DesiredWorkerLabels, + DisplayName: runOpts.DisplayName, }) } else { v0Workflow, err = c.legacyClient.Admin().RunWorkflow(workflowName, input, v0Opts...) diff --git a/sdks/go/display_name_test.go b/sdks/go/display_name_test.go new file mode 100644 index 0000000000..d1b869090c --- /dev/null +++ b/sdks/go/display_name_test.go @@ -0,0 +1,27 @@ +package hatchet + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestWithRunDisplayName_setsRunOpt(t *testing.T) { + opts := &runOpts{} + + WithRunDisplayName("Acme Corp")(opts) + + require.NotNil(t, opts.DisplayName) + assert.Equal(t, "Acme Corp", *opts.DisplayName) +} + +func TestRunOpts_displayNameUnsetByDefault(t *testing.T) { + opts := &runOpts{} + + for _, opt := range []RunOptFunc{WithRunKey("k"), WithRunSticky(true)} { + opt(opts) + } + + assert.Nil(t, opts.DisplayName, "display name stays unset unless WithRunDisplayName is used") +} diff --git a/sdks/go/durable_child.go b/sdks/go/durable_child.go index f3620f5a11..16fec501ed 100644 --- a/sdks/go/durable_child.go +++ b/sdks/go/durable_child.go @@ -200,6 +200,7 @@ func durableChildWorkflowOpts( AdditionalMetadata: runOpts.AdditionalMetadata, Priority: priority, DesiredWorkerLabels: runOpts.DesiredWorkerLabels, + DisplayName: runOpts.DisplayName, }, nil } diff --git a/sdks/go/workflow.go b/sdks/go/workflow.go index c018f95195..a97d12c2c0 100644 --- a/sdks/go/workflow.go +++ b/sdks/go/workflow.go @@ -59,6 +59,7 @@ type runOpts struct { Sticky *bool Key *string DesiredWorkerLabels map[string]*DesiredWorkerLabel + DisplayName *string } type RunOptFunc func(*runOpts) @@ -91,6 +92,14 @@ func WithRunKey(key string) RunOptFunc { } } +// WithRunDisplayName sets a custom display name for the workflow run. The engine +// trims and truncates it; an empty/whitespace value falls back to the generated name. +func WithRunDisplayName(displayName string) RunOptFunc { + return func(opts *runOpts) { + opts.DisplayName = &displayName + } +} + // WithDesiredWorkerLabels sets desired worker labels for routing the workflow run to specific workers. func WithDesiredWorkerLabels(labels map[string]*DesiredWorkerLabel) RunOptFunc { return func(opts *runOpts) { @@ -698,6 +707,10 @@ func (w *Workflow) runWorkflowInternal(ctx context.Context, otelCtx context.Cont v0Opts = append(v0Opts, v0Client.WithDesiredWorkerLabels(runOpts.DesiredWorkerLabels)) } + if runOpts.DisplayName != nil { + v0Opts = append(v0Opts, v0Client.WithDisplayName(*runOpts.DisplayName)) + } + var v0Workflow *v0Client.Workflow var err error @@ -720,6 +733,7 @@ func (w *Workflow) runWorkflowInternal(ctx context.Context, otelCtx context.Cont Priority: priority, AdditionalMetadata: runOpts.AdditionalMetadata, DesiredWorkerLabels: runOpts.DesiredWorkerLabels, + DisplayName: runOpts.DisplayName, }) } else { v0Workflow, err = w.v0Client.Admin().RunWorkflow(w.declaration.Name(), input, v0Opts...) diff --git a/sdks/python/CHANGELOG.md b/sdks/python/CHANGELOG.md index 2b5364bcdf..e39299632e 100644 --- a/sdks/python/CHANGELOG.md +++ b/sdks/python/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to Hatchet's Python SDK will be documented in this changelog The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Added + +- Added a `display_name` option to set a custom, human-readable name on a run at trigger time. It is accepted as a direct keyword argument on every run surface (`run`, `run_no_wait`, `aio_run`, `aio_run_no_wait`, per-item via `create_bulk_run_item` for `run_many`, and child spawns) and on `TriggerWorkflowOptions`. Single-task runs carry the name on the task; multi-step DAG runs carry it on the DAG (the DAG's step tasks keep their generated names). Empty or whitespace-only values fall back to the generated `-` name, and names longer than 255 characters are stored truncated rather than rejected ([#4259](https://github.com/hatchet-dev/hatchet/issues/4259)). + ## [1.33.12] - 2026-06-21 ### Fixed diff --git a/sdks/python/hatchet_sdk/clients/admin.py b/sdks/python/hatchet_sdk/clients/admin.py index e47400a1c4..bcdec33cc4 100644 --- a/sdks/python/hatchet_sdk/clients/admin.py +++ b/sdks/python/hatchet_sdk/clients/admin.py @@ -164,6 +164,7 @@ class TriggerWorkflowRequest(BaseModel): desired_worker_label: ( dict[str, DesiredWorkerLabel] | list[DesiredWorkerLabel] | None ) = None + display_name: str | None = None @field_validator("additional_metadata", mode="before") @classmethod @@ -219,6 +220,7 @@ def _prepare_workflow_request( desired_worker_id=_options.desired_worker_id, priority=_options.priority, desired_worker_labels=desired_worker_labels, + display_name=_options.display_name, ) def _parse_schedule(self, schedule: datetime) -> timestamp_pb2.Timestamp: @@ -395,6 +397,7 @@ def _create_workflow_run_request( sticky=options.sticky, key=options.key, desired_worker_label=options.desired_worker_label, + display_name=options.display_name, ) namespace = options.namespace or self.namespace diff --git a/sdks/python/hatchet_sdk/contracts/v1/shared/trigger_pb2.py b/sdks/python/hatchet_sdk/contracts/v1/shared/trigger_pb2.py index a1e6b14f14..e568e7c308 100644 --- a/sdks/python/hatchet_sdk/contracts/v1/shared/trigger_pb2.py +++ b/sdks/python/hatchet_sdk/contracts/v1/shared/trigger_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: v1/shared/trigger.proto -# Protobuf Python Version: 6.31.1 +# Protobuf Python Version: 6.33.5 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -12,8 +12,8 @@ _runtime_version.ValidateProtobufRuntimeVersion( _runtime_version.Domain.PUBLIC, 6, - 31, - 1, + 33, + 5, '', 'v1/shared/trigger.proto' ) @@ -24,7 +24,7 @@ -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17v1/shared/trigger.proto\x12\x02v1\"\xe8\x01\n\x13\x44\x65siredWorkerLabels\x12\x16\n\tstr_value\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x16\n\tint_value\x18\x02 \x01(\x05H\x01\x88\x01\x01\x12\x15\n\x08required\x18\x03 \x01(\x08H\x02\x88\x01\x01\x12\x32\n\ncomparator\x18\x04 \x01(\x0e\x32\x19.v1.WorkerLabelComparatorH\x03\x88\x01\x01\x12\x13\n\x06weight\x18\x05 \x01(\x05H\x04\x88\x01\x01\x42\x0c\n\n_str_valueB\x0c\n\n_int_valueB\x0b\n\t_requiredB\r\n\x0b_comparatorB\t\n\x07_weight\"\xb2\x04\n\x16TriggerWorkflowRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05input\x18\x02 \x01(\t\x12\x16\n\tparent_id\x18\x03 \x01(\tH\x00\x88\x01\x01\x12(\n\x1bparent_task_run_external_id\x18\x04 \x01(\tH\x01\x88\x01\x01\x12\x18\n\x0b\x63hild_index\x18\x05 \x01(\x05H\x02\x88\x01\x01\x12\x16\n\tchild_key\x18\x06 \x01(\tH\x03\x88\x01\x01\x12 \n\x13\x61\x64\x64itional_metadata\x18\x07 \x01(\tH\x04\x88\x01\x01\x12\x1e\n\x11\x64\x65sired_worker_id\x18\x08 \x01(\tH\x05\x88\x01\x01\x12\x15\n\x08priority\x18\t \x01(\x05H\x06\x88\x01\x01\x12R\n\x15\x64\x65sired_worker_labels\x18\n \x03(\x0b\x32\x33.v1.TriggerWorkflowRequest.DesiredWorkerLabelsEntry\x1aS\n\x18\x44\x65siredWorkerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.v1.DesiredWorkerLabels:\x02\x38\x01\x42\x0c\n\n_parent_idB\x1e\n\x1c_parent_task_run_external_idB\x0e\n\x0c_child_indexB\x0c\n\n_child_keyB\x16\n\x14_additional_metadataB\x14\n\x12_desired_worker_idB\x0b\n\t_priority*\x85\x01\n\x15WorkerLabelComparator\x12\t\n\x05\x45QUAL\x10\x00\x12\r\n\tNOT_EQUAL\x10\x01\x12\x10\n\x0cGREATER_THAN\x10\x02\x12\x19\n\x15GREATER_THAN_OR_EQUAL\x10\x03\x12\r\n\tLESS_THAN\x10\x04\x12\x16\n\x12LESS_THAN_OR_EQUAL\x10\x05\x42\x42Z@github.com/hatchet-dev/hatchet/internal/services/shared/proto/v1b\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17v1/shared/trigger.proto\x12\x02v1\"\xe8\x01\n\x13\x44\x65siredWorkerLabels\x12\x16\n\tstr_value\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x16\n\tint_value\x18\x02 \x01(\x05H\x01\x88\x01\x01\x12\x15\n\x08required\x18\x03 \x01(\x08H\x02\x88\x01\x01\x12\x32\n\ncomparator\x18\x04 \x01(\x0e\x32\x19.v1.WorkerLabelComparatorH\x03\x88\x01\x01\x12\x13\n\x06weight\x18\x05 \x01(\x05H\x04\x88\x01\x01\x42\x0c\n\n_str_valueB\x0c\n\n_int_valueB\x0b\n\t_requiredB\r\n\x0b_comparatorB\t\n\x07_weight\"\xde\x04\n\x16TriggerWorkflowRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05input\x18\x02 \x01(\t\x12\x16\n\tparent_id\x18\x03 \x01(\tH\x00\x88\x01\x01\x12(\n\x1bparent_task_run_external_id\x18\x04 \x01(\tH\x01\x88\x01\x01\x12\x18\n\x0b\x63hild_index\x18\x05 \x01(\x05H\x02\x88\x01\x01\x12\x16\n\tchild_key\x18\x06 \x01(\tH\x03\x88\x01\x01\x12 \n\x13\x61\x64\x64itional_metadata\x18\x07 \x01(\tH\x04\x88\x01\x01\x12\x1e\n\x11\x64\x65sired_worker_id\x18\x08 \x01(\tH\x05\x88\x01\x01\x12\x15\n\x08priority\x18\t \x01(\x05H\x06\x88\x01\x01\x12R\n\x15\x64\x65sired_worker_labels\x18\n \x03(\x0b\x32\x33.v1.TriggerWorkflowRequest.DesiredWorkerLabelsEntry\x12\x19\n\x0c\x64isplay_name\x18\x0b \x01(\tH\x07\x88\x01\x01\x1aS\n\x18\x44\x65siredWorkerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.v1.DesiredWorkerLabels:\x02\x38\x01\x42\x0c\n\n_parent_idB\x1e\n\x1c_parent_task_run_external_idB\x0e\n\x0c_child_indexB\x0c\n\n_child_keyB\x16\n\x14_additional_metadataB\x14\n\x12_desired_worker_idB\x0b\n\t_priorityB\x0f\n\r_display_name*\x85\x01\n\x15WorkerLabelComparator\x12\t\n\x05\x45QUAL\x10\x00\x12\r\n\tNOT_EQUAL\x10\x01\x12\x10\n\x0cGREATER_THAN\x10\x02\x12\x19\n\x15GREATER_THAN_OR_EQUAL\x10\x03\x12\r\n\tLESS_THAN\x10\x04\x12\x16\n\x12LESS_THAN_OR_EQUAL\x10\x05\x42\x42Z@github.com/hatchet-dev/hatchet/internal/services/shared/proto/v1b\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -34,12 +34,12 @@ _globals['DESCRIPTOR']._serialized_options = b'Z@github.com/hatchet-dev/hatchet/internal/services/shared/proto/v1' _globals['_TRIGGERWORKFLOWREQUEST_DESIREDWORKERLABELSENTRY']._loaded_options = None _globals['_TRIGGERWORKFLOWREQUEST_DESIREDWORKERLABELSENTRY']._serialized_options = b'8\001' - _globals['_WORKERLABELCOMPARATOR']._serialized_start=832 - _globals['_WORKERLABELCOMPARATOR']._serialized_end=965 + _globals['_WORKERLABELCOMPARATOR']._serialized_start=876 + _globals['_WORKERLABELCOMPARATOR']._serialized_end=1009 _globals['_DESIREDWORKERLABELS']._serialized_start=32 _globals['_DESIREDWORKERLABELS']._serialized_end=264 _globals['_TRIGGERWORKFLOWREQUEST']._serialized_start=267 - _globals['_TRIGGERWORKFLOWREQUEST']._serialized_end=829 - _globals['_TRIGGERWORKFLOWREQUEST_DESIREDWORKERLABELSENTRY']._serialized_start=611 - _globals['_TRIGGERWORKFLOWREQUEST_DESIREDWORKERLABELSENTRY']._serialized_end=694 + _globals['_TRIGGERWORKFLOWREQUEST']._serialized_end=873 + _globals['_TRIGGERWORKFLOWREQUEST_DESIREDWORKERLABELSENTRY']._serialized_start=638 + _globals['_TRIGGERWORKFLOWREQUEST_DESIREDWORKERLABELSENTRY']._serialized_end=721 # @@protoc_insertion_point(module_scope) diff --git a/sdks/python/hatchet_sdk/contracts/v1/shared/trigger_pb2.pyi b/sdks/python/hatchet_sdk/contracts/v1/shared/trigger_pb2.pyi index 28aefdcb4b..852f136210 100644 --- a/sdks/python/hatchet_sdk/contracts/v1/shared/trigger_pb2.pyi +++ b/sdks/python/hatchet_sdk/contracts/v1/shared/trigger_pb2.pyi @@ -34,10 +34,10 @@ class DesiredWorkerLabels(_message.Message): required: bool comparator: WorkerLabelComparator weight: int - def __init__(self, str_value: _Optional[str] = ..., int_value: _Optional[int] = ..., required: bool = ..., comparator: _Optional[_Union[WorkerLabelComparator, str]] = ..., weight: _Optional[int] = ...) -> None: ... + def __init__(self, str_value: _Optional[str] = ..., int_value: _Optional[int] = ..., required: _Optional[bool] = ..., comparator: _Optional[_Union[WorkerLabelComparator, str]] = ..., weight: _Optional[int] = ...) -> None: ... class TriggerWorkflowRequest(_message.Message): - __slots__ = ("name", "input", "parent_id", "parent_task_run_external_id", "child_index", "child_key", "additional_metadata", "desired_worker_id", "priority", "desired_worker_labels") + __slots__ = ("name", "input", "parent_id", "parent_task_run_external_id", "child_index", "child_key", "additional_metadata", "desired_worker_id", "priority", "desired_worker_labels", "display_name") class DesiredWorkerLabelsEntry(_message.Message): __slots__ = ("key", "value") KEY_FIELD_NUMBER: _ClassVar[int] @@ -55,6 +55,7 @@ class TriggerWorkflowRequest(_message.Message): DESIRED_WORKER_ID_FIELD_NUMBER: _ClassVar[int] PRIORITY_FIELD_NUMBER: _ClassVar[int] DESIRED_WORKER_LABELS_FIELD_NUMBER: _ClassVar[int] + DISPLAY_NAME_FIELD_NUMBER: _ClassVar[int] name: str input: str parent_id: str @@ -65,4 +66,5 @@ class TriggerWorkflowRequest(_message.Message): desired_worker_id: str priority: int desired_worker_labels: _containers.MessageMap[str, DesiredWorkerLabels] - def __init__(self, name: _Optional[str] = ..., input: _Optional[str] = ..., parent_id: _Optional[str] = ..., parent_task_run_external_id: _Optional[str] = ..., child_index: _Optional[int] = ..., child_key: _Optional[str] = ..., additional_metadata: _Optional[str] = ..., desired_worker_id: _Optional[str] = ..., priority: _Optional[int] = ..., desired_worker_labels: _Optional[_Mapping[str, DesiredWorkerLabels]] = ...) -> None: ... + display_name: str + def __init__(self, name: _Optional[str] = ..., input: _Optional[str] = ..., parent_id: _Optional[str] = ..., parent_task_run_external_id: _Optional[str] = ..., child_index: _Optional[int] = ..., child_key: _Optional[str] = ..., additional_metadata: _Optional[str] = ..., desired_worker_id: _Optional[str] = ..., priority: _Optional[int] = ..., desired_worker_labels: _Optional[_Mapping[str, DesiredWorkerLabels]] = ..., display_name: _Optional[str] = ...) -> None: ... diff --git a/sdks/python/hatchet_sdk/contracts/v1/workflows_pb2.py b/sdks/python/hatchet_sdk/contracts/v1/workflows_pb2.py index 3a9ab133c1..d04a10a724 100644 --- a/sdks/python/hatchet_sdk/contracts/v1/workflows_pb2.py +++ b/sdks/python/hatchet_sdk/contracts/v1/workflows_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: v1/workflows.proto -# Protobuf Python Version: 6.31.1 +# Protobuf Python Version: 6.33.5 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -12,8 +12,8 @@ _runtime_version.ValidateProtobufRuntimeVersion( _runtime_version.Domain.PUBLIC, 6, - 31, - 1, + 33, + 5, '', 'v1/workflows.proto' ) @@ -27,7 +27,7 @@ from hatchet_sdk.contracts.v1.shared import trigger_pb2 as v1_dot_shared_dot_trigger__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x12v1/workflows.proto\x12\x02v1\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x19v1/shared/condition.proto\x1a\x17v1/shared/trigger.proto\"[\n\x12\x43\x61ncelTasksRequest\x12\x14\n\x0c\x65xternal_ids\x18\x01 \x03(\t\x12$\n\x06\x66ilter\x18\x02 \x01(\x0b\x32\x0f.v1.TasksFilterH\x00\x88\x01\x01\x42\t\n\x07_filter\"[\n\x12ReplayTasksRequest\x12\x14\n\x0c\x65xternal_ids\x18\x01 \x03(\t\x12$\n\x06\x66ilter\x18\x02 \x01(\x0b\x32\x0f.v1.TasksFilterH\x00\x88\x01\x01\x42\t\n\x07_filter\"\xb7\x01\n\x0bTasksFilter\x12\x10\n\x08statuses\x18\x01 \x03(\t\x12)\n\x05since\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\x05until\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x88\x01\x01\x12\x14\n\x0cworkflow_ids\x18\x04 \x03(\t\x12\x1b\n\x13\x61\x64\x64itional_metadata\x18\x05 \x03(\tB\x08\n\x06_until\".\n\x13\x43\x61ncelTasksResponse\x12\x17\n\x0f\x63\x61ncelled_tasks\x18\x01 \x03(\t\"-\n\x13ReplayTasksResponse\x12\x16\n\x0ereplayed_tasks\x18\x01 \x03(\t\"\xae\x02\n\x19TriggerWorkflowRunRequest\x12\x15\n\rworkflow_name\x18\x01 \x01(\t\x12\r\n\x05input\x18\x02 \x01(\x0c\x12\x1b\n\x13\x61\x64\x64itional_metadata\x18\x03 \x01(\x0c\x12\x15\n\x08priority\x18\x04 \x01(\x05H\x00\x88\x01\x01\x12U\n\x15\x64\x65sired_worker_labels\x18\x05 \x03(\x0b\x32\x36.v1.TriggerWorkflowRunRequest.DesiredWorkerLabelsEntry\x1aS\n\x18\x44\x65siredWorkerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.v1.DesiredWorkerLabels:\x02\x38\x01\x42\x0b\n\t_priority\"1\n\x1aTriggerWorkflowRunResponse\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\"X\n\x18\x42ranchDurableTaskRequest\x12\x18\n\x10task_external_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\x03\x12\x11\n\tbranch_id\x18\x03 \x01(\x03\"Y\n\x19\x42ranchDurableTaskResponse\x12\x18\n\x10task_external_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\x03\x12\x11\n\tbranch_id\x18\x03 \x01(\x03\"\xac\x04\n\x1c\x43reateWorkflowVersionRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x0f\n\x07version\x18\x03 \x01(\t\x12\x16\n\x0e\x65vent_triggers\x18\x04 \x03(\t\x12\x15\n\rcron_triggers\x18\x05 \x03(\t\x12!\n\x05tasks\x18\x06 \x03(\x0b\x32\x12.v1.CreateTaskOpts\x12$\n\x0b\x63oncurrency\x18\x07 \x01(\x0b\x32\x0f.v1.Concurrency\x12\x17\n\ncron_input\x18\x08 \x01(\tH\x00\x88\x01\x01\x12\x30\n\x0fon_failure_task\x18\t \x01(\x0b\x32\x12.v1.CreateTaskOptsH\x01\x88\x01\x01\x12\'\n\x06sticky\x18\n \x01(\x0e\x32\x12.v1.StickyStrategyH\x02\x88\x01\x01\x12\x1d\n\x10\x64\x65\x66\x61ult_priority\x18\x0b \x01(\x05H\x03\x88\x01\x01\x12(\n\x0f\x63oncurrency_arr\x18\x0c \x03(\x0b\x32\x0f.v1.Concurrency\x12*\n\x0f\x64\x65\x66\x61ult_filters\x18\r \x03(\x0b\x32\x11.v1.DefaultFilter\x12\x1e\n\x11input_json_schema\x18\x0e \x01(\x0cH\x04\x88\x01\x01\x42\r\n\x0b_cron_inputB\x12\n\x10_on_failure_taskB\t\n\x07_stickyB\x13\n\x11_default_priorityB\x14\n\x12_input_json_schema\"T\n\rDefaultFilter\x12\x12\n\nexpression\x18\x01 \x01(\t\x12\r\n\x05scope\x18\x02 \x01(\t\x12\x14\n\x07payload\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x42\n\n\x08_payload\"\x93\x01\n\x0b\x43oncurrency\x12\x12\n\nexpression\x18\x01 \x01(\t\x12\x15\n\x08max_runs\x18\x02 \x01(\x05H\x00\x88\x01\x01\x12\x39\n\x0elimit_strategy\x18\x03 \x01(\x0e\x32\x1c.v1.ConcurrencyLimitStrategyH\x01\x88\x01\x01\x42\x0b\n\t_max_runsB\x11\n\x0f_limit_strategy\"\xb7\x05\n\x0e\x43reateTaskOpts\x12\x13\n\x0breadable_id\x18\x01 \x01(\t\x12\x0e\n\x06\x61\x63tion\x18\x02 \x01(\t\x12\x0f\n\x07timeout\x18\x03 \x01(\t\x12\x0e\n\x06inputs\x18\x04 \x01(\t\x12\x0f\n\x07parents\x18\x05 \x03(\t\x12\x0f\n\x07retries\x18\x06 \x01(\x05\x12,\n\x0brate_limits\x18\x07 \x03(\x0b\x32\x17.v1.CreateTaskRateLimit\x12;\n\rworker_labels\x18\x08 \x03(\x0b\x32$.v1.CreateTaskOpts.WorkerLabelsEntry\x12\x1b\n\x0e\x62\x61\x63koff_factor\x18\t \x01(\x02H\x00\x88\x01\x01\x12 \n\x13\x62\x61\x63koff_max_seconds\x18\n \x01(\x05H\x01\x88\x01\x01\x12$\n\x0b\x63oncurrency\x18\x0b \x03(\x0b\x32\x0f.v1.Concurrency\x12+\n\nconditions\x18\x0c \x01(\x0b\x32\x12.v1.TaskConditionsH\x02\x88\x01\x01\x12\x1d\n\x10schedule_timeout\x18\r \x01(\tH\x03\x88\x01\x01\x12\x12\n\nis_durable\x18\x0e \x01(\x08\x12;\n\rslot_requests\x18\x0f \x03(\x0b\x32$.v1.CreateTaskOpts.SlotRequestsEntry\x1aL\n\x11WorkerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.v1.DesiredWorkerLabels:\x02\x38\x01\x1a\x33\n\x11SlotRequestsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x42\x11\n\x0f_backoff_factorB\x16\n\x14_backoff_max_secondsB\r\n\x0b_conditionsB\x13\n\x11_schedule_timeout\"\xfd\x01\n\x13\x43reateTaskRateLimit\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x12\n\x05units\x18\x02 \x01(\x05H\x00\x88\x01\x01\x12\x15\n\x08key_expr\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x17\n\nunits_expr\x18\x04 \x01(\tH\x02\x88\x01\x01\x12\x1e\n\x11limit_values_expr\x18\x05 \x01(\tH\x03\x88\x01\x01\x12,\n\x08\x64uration\x18\x06 \x01(\x0e\x32\x15.v1.RateLimitDurationH\x04\x88\x01\x01\x42\x08\n\x06_unitsB\x0b\n\t_key_exprB\r\n\x0b_units_exprB\x14\n\x12_limit_values_exprB\x0b\n\t_duration\"@\n\x1d\x43reateWorkflowVersionResponse\x12\n\n\x02id\x18\x01 \x01(\t\x12\x13\n\x0bworkflow_id\x18\x02 \x01(\t\"+\n\x14GetRunDetailsRequest\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\"\xaa\x01\n\rTaskRunDetail\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\x12\x1d\n\x06status\x18\x02 \x01(\x0e\x32\r.v1.RunStatus\x12\x12\n\x05\x65rror\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06output\x18\x04 \x01(\x0cH\x01\x88\x01\x01\x12\x13\n\x0breadable_id\x18\x05 \x01(\t\x12\x12\n\nis_evicted\x18\x06 \x01(\x08\x42\x08\n\x06_errorB\t\n\x07_output\"\x84\x02\n\x15GetRunDetailsResponse\x12\r\n\x05input\x18\x01 \x01(\x0c\x12\x1d\n\x06status\x18\x02 \x01(\x0e\x32\r.v1.RunStatus\x12:\n\ttask_runs\x18\x03 \x03(\x0b\x32\'.v1.GetRunDetailsResponse.TaskRunsEntry\x12\x0c\n\x04\x64one\x18\x04 \x01(\x08\x12\x1b\n\x13\x61\x64\x64itional_metadata\x18\x05 \x01(\x0c\x12\x12\n\nis_evicted\x18\x06 \x01(\x08\x1a\x42\n\rTaskRunsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12 \n\x05value\x18\x02 \x01(\x0b\x32\x11.v1.TaskRunDetail:\x02\x38\x01*$\n\x0eStickyStrategy\x12\x08\n\x04SOFT\x10\x00\x12\x08\n\x04HARD\x10\x01*]\n\x11RateLimitDuration\x12\n\n\x06SECOND\x10\x00\x12\n\n\x06MINUTE\x10\x01\x12\x08\n\x04HOUR\x10\x02\x12\x07\n\x03\x44\x41Y\x10\x03\x12\x08\n\x04WEEK\x10\x04\x12\t\n\x05MONTH\x10\x05\x12\x08\n\x04YEAR\x10\x06*[\n\tRunStatus\x12\n\n\x06QUEUED\x10\x00\x12\x0b\n\x07RUNNING\x10\x01\x12\r\n\tCOMPLETED\x10\x02\x12\n\n\x06\x46\x41ILED\x10\x03\x12\r\n\tCANCELLED\x10\x04\x12\x0b\n\x07\x45VICTED\x10\x05*\x7f\n\x18\x43oncurrencyLimitStrategy\x12\x16\n\x12\x43\x41NCEL_IN_PROGRESS\x10\x00\x12\x0f\n\x0b\x44ROP_NEWEST\x10\x01\x12\x10\n\x0cQUEUE_NEWEST\x10\x02\x12\x15\n\x11GROUP_ROUND_ROBIN\x10\x03\x12\x11\n\rCANCEL_NEWEST\x10\x04\x32\xcf\x03\n\x0c\x41\x64minService\x12R\n\x0bPutWorkflow\x12 .v1.CreateWorkflowVersionRequest\x1a!.v1.CreateWorkflowVersionResponse\x12>\n\x0b\x43\x61ncelTasks\x12\x16.v1.CancelTasksRequest\x1a\x17.v1.CancelTasksResponse\x12>\n\x0bReplayTasks\x12\x16.v1.ReplayTasksRequest\x1a\x17.v1.ReplayTasksResponse\x12S\n\x12TriggerWorkflowRun\x12\x1d.v1.TriggerWorkflowRunRequest\x1a\x1e.v1.TriggerWorkflowRunResponse\x12\x44\n\rGetRunDetails\x12\x18.v1.GetRunDetailsRequest\x1a\x19.v1.GetRunDetailsResponse\x12P\n\x11\x42ranchDurableTask\x12\x1c.v1.BranchDurableTaskRequest\x1a\x1d.v1.BranchDurableTaskResponseBBZ@github.com/hatchet-dev/hatchet/internal/services/shared/proto/v1b\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x12v1/workflows.proto\x12\x02v1\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x19v1/shared/condition.proto\x1a\x17v1/shared/trigger.proto\"[\n\x12\x43\x61ncelTasksRequest\x12\x14\n\x0c\x65xternal_ids\x18\x01 \x03(\t\x12$\n\x06\x66ilter\x18\x02 \x01(\x0b\x32\x0f.v1.TasksFilterH\x00\x88\x01\x01\x42\t\n\x07_filter\"[\n\x12ReplayTasksRequest\x12\x14\n\x0c\x65xternal_ids\x18\x01 \x03(\t\x12$\n\x06\x66ilter\x18\x02 \x01(\x0b\x32\x0f.v1.TasksFilterH\x00\x88\x01\x01\x42\t\n\x07_filter\"\xb7\x01\n\x0bTasksFilter\x12\x10\n\x08statuses\x18\x01 \x03(\t\x12)\n\x05since\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\x05until\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x88\x01\x01\x12\x14\n\x0cworkflow_ids\x18\x04 \x03(\t\x12\x1b\n\x13\x61\x64\x64itional_metadata\x18\x05 \x03(\tB\x08\n\x06_until\".\n\x13\x43\x61ncelTasksResponse\x12\x17\n\x0f\x63\x61ncelled_tasks\x18\x01 \x03(\t\"-\n\x13ReplayTasksResponse\x12\x16\n\x0ereplayed_tasks\x18\x01 \x03(\t\"\xda\x02\n\x19TriggerWorkflowRunRequest\x12\x15\n\rworkflow_name\x18\x01 \x01(\t\x12\r\n\x05input\x18\x02 \x01(\x0c\x12\x1b\n\x13\x61\x64\x64itional_metadata\x18\x03 \x01(\x0c\x12\x15\n\x08priority\x18\x04 \x01(\x05H\x00\x88\x01\x01\x12U\n\x15\x64\x65sired_worker_labels\x18\x05 \x03(\x0b\x32\x36.v1.TriggerWorkflowRunRequest.DesiredWorkerLabelsEntry\x12\x19\n\x0c\x64isplay_name\x18\x06 \x01(\tH\x01\x88\x01\x01\x1aS\n\x18\x44\x65siredWorkerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.v1.DesiredWorkerLabels:\x02\x38\x01\x42\x0b\n\t_priorityB\x0f\n\r_display_name\"1\n\x1aTriggerWorkflowRunResponse\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\"X\n\x18\x42ranchDurableTaskRequest\x12\x18\n\x10task_external_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\x03\x12\x11\n\tbranch_id\x18\x03 \x01(\x03\"Y\n\x19\x42ranchDurableTaskResponse\x12\x18\n\x10task_external_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\x03\x12\x11\n\tbranch_id\x18\x03 \x01(\x03\"\xac\x04\n\x1c\x43reateWorkflowVersionRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x0f\n\x07version\x18\x03 \x01(\t\x12\x16\n\x0e\x65vent_triggers\x18\x04 \x03(\t\x12\x15\n\rcron_triggers\x18\x05 \x03(\t\x12!\n\x05tasks\x18\x06 \x03(\x0b\x32\x12.v1.CreateTaskOpts\x12$\n\x0b\x63oncurrency\x18\x07 \x01(\x0b\x32\x0f.v1.Concurrency\x12\x17\n\ncron_input\x18\x08 \x01(\tH\x00\x88\x01\x01\x12\x30\n\x0fon_failure_task\x18\t \x01(\x0b\x32\x12.v1.CreateTaskOptsH\x01\x88\x01\x01\x12\'\n\x06sticky\x18\n \x01(\x0e\x32\x12.v1.StickyStrategyH\x02\x88\x01\x01\x12\x1d\n\x10\x64\x65\x66\x61ult_priority\x18\x0b \x01(\x05H\x03\x88\x01\x01\x12(\n\x0f\x63oncurrency_arr\x18\x0c \x03(\x0b\x32\x0f.v1.Concurrency\x12*\n\x0f\x64\x65\x66\x61ult_filters\x18\r \x03(\x0b\x32\x11.v1.DefaultFilter\x12\x1e\n\x11input_json_schema\x18\x0e \x01(\x0cH\x04\x88\x01\x01\x42\r\n\x0b_cron_inputB\x12\n\x10_on_failure_taskB\t\n\x07_stickyB\x13\n\x11_default_priorityB\x14\n\x12_input_json_schema\"T\n\rDefaultFilter\x12\x12\n\nexpression\x18\x01 \x01(\t\x12\r\n\x05scope\x18\x02 \x01(\t\x12\x14\n\x07payload\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x42\n\n\x08_payload\"\x93\x01\n\x0b\x43oncurrency\x12\x12\n\nexpression\x18\x01 \x01(\t\x12\x15\n\x08max_runs\x18\x02 \x01(\x05H\x00\x88\x01\x01\x12\x39\n\x0elimit_strategy\x18\x03 \x01(\x0e\x32\x1c.v1.ConcurrencyLimitStrategyH\x01\x88\x01\x01\x42\x0b\n\t_max_runsB\x11\n\x0f_limit_strategy\"\xb7\x05\n\x0e\x43reateTaskOpts\x12\x13\n\x0breadable_id\x18\x01 \x01(\t\x12\x0e\n\x06\x61\x63tion\x18\x02 \x01(\t\x12\x0f\n\x07timeout\x18\x03 \x01(\t\x12\x0e\n\x06inputs\x18\x04 \x01(\t\x12\x0f\n\x07parents\x18\x05 \x03(\t\x12\x0f\n\x07retries\x18\x06 \x01(\x05\x12,\n\x0brate_limits\x18\x07 \x03(\x0b\x32\x17.v1.CreateTaskRateLimit\x12;\n\rworker_labels\x18\x08 \x03(\x0b\x32$.v1.CreateTaskOpts.WorkerLabelsEntry\x12\x1b\n\x0e\x62\x61\x63koff_factor\x18\t \x01(\x02H\x00\x88\x01\x01\x12 \n\x13\x62\x61\x63koff_max_seconds\x18\n \x01(\x05H\x01\x88\x01\x01\x12$\n\x0b\x63oncurrency\x18\x0b \x03(\x0b\x32\x0f.v1.Concurrency\x12+\n\nconditions\x18\x0c \x01(\x0b\x32\x12.v1.TaskConditionsH\x02\x88\x01\x01\x12\x1d\n\x10schedule_timeout\x18\r \x01(\tH\x03\x88\x01\x01\x12\x12\n\nis_durable\x18\x0e \x01(\x08\x12;\n\rslot_requests\x18\x0f \x03(\x0b\x32$.v1.CreateTaskOpts.SlotRequestsEntry\x1aL\n\x11WorkerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.v1.DesiredWorkerLabels:\x02\x38\x01\x1a\x33\n\x11SlotRequestsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x42\x11\n\x0f_backoff_factorB\x16\n\x14_backoff_max_secondsB\r\n\x0b_conditionsB\x13\n\x11_schedule_timeout\"\xfd\x01\n\x13\x43reateTaskRateLimit\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x12\n\x05units\x18\x02 \x01(\x05H\x00\x88\x01\x01\x12\x15\n\x08key_expr\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x17\n\nunits_expr\x18\x04 \x01(\tH\x02\x88\x01\x01\x12\x1e\n\x11limit_values_expr\x18\x05 \x01(\tH\x03\x88\x01\x01\x12,\n\x08\x64uration\x18\x06 \x01(\x0e\x32\x15.v1.RateLimitDurationH\x04\x88\x01\x01\x42\x08\n\x06_unitsB\x0b\n\t_key_exprB\r\n\x0b_units_exprB\x14\n\x12_limit_values_exprB\x0b\n\t_duration\"@\n\x1d\x43reateWorkflowVersionResponse\x12\n\n\x02id\x18\x01 \x01(\t\x12\x13\n\x0bworkflow_id\x18\x02 \x01(\t\"+\n\x14GetRunDetailsRequest\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\"\xaa\x01\n\rTaskRunDetail\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\x12\x1d\n\x06status\x18\x02 \x01(\x0e\x32\r.v1.RunStatus\x12\x12\n\x05\x65rror\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06output\x18\x04 \x01(\x0cH\x01\x88\x01\x01\x12\x13\n\x0breadable_id\x18\x05 \x01(\t\x12\x12\n\nis_evicted\x18\x06 \x01(\x08\x42\x08\n\x06_errorB\t\n\x07_output\"\x84\x02\n\x15GetRunDetailsResponse\x12\r\n\x05input\x18\x01 \x01(\x0c\x12\x1d\n\x06status\x18\x02 \x01(\x0e\x32\r.v1.RunStatus\x12:\n\ttask_runs\x18\x03 \x03(\x0b\x32\'.v1.GetRunDetailsResponse.TaskRunsEntry\x12\x0c\n\x04\x64one\x18\x04 \x01(\x08\x12\x1b\n\x13\x61\x64\x64itional_metadata\x18\x05 \x01(\x0c\x12\x12\n\nis_evicted\x18\x06 \x01(\x08\x1a\x42\n\rTaskRunsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12 \n\x05value\x18\x02 \x01(\x0b\x32\x11.v1.TaskRunDetail:\x02\x38\x01*$\n\x0eStickyStrategy\x12\x08\n\x04SOFT\x10\x00\x12\x08\n\x04HARD\x10\x01*]\n\x11RateLimitDuration\x12\n\n\x06SECOND\x10\x00\x12\n\n\x06MINUTE\x10\x01\x12\x08\n\x04HOUR\x10\x02\x12\x07\n\x03\x44\x41Y\x10\x03\x12\x08\n\x04WEEK\x10\x04\x12\t\n\x05MONTH\x10\x05\x12\x08\n\x04YEAR\x10\x06*[\n\tRunStatus\x12\n\n\x06QUEUED\x10\x00\x12\x0b\n\x07RUNNING\x10\x01\x12\r\n\tCOMPLETED\x10\x02\x12\n\n\x06\x46\x41ILED\x10\x03\x12\r\n\tCANCELLED\x10\x04\x12\x0b\n\x07\x45VICTED\x10\x05*\x7f\n\x18\x43oncurrencyLimitStrategy\x12\x16\n\x12\x43\x41NCEL_IN_PROGRESS\x10\x00\x12\x0f\n\x0b\x44ROP_NEWEST\x10\x01\x12\x10\n\x0cQUEUE_NEWEST\x10\x02\x12\x15\n\x11GROUP_ROUND_ROBIN\x10\x03\x12\x11\n\rCANCEL_NEWEST\x10\x04\x32\xcf\x03\n\x0c\x41\x64minService\x12R\n\x0bPutWorkflow\x12 .v1.CreateWorkflowVersionRequest\x1a!.v1.CreateWorkflowVersionResponse\x12>\n\x0b\x43\x61ncelTasks\x12\x16.v1.CancelTasksRequest\x1a\x17.v1.CancelTasksResponse\x12>\n\x0bReplayTasks\x12\x16.v1.ReplayTasksRequest\x1a\x17.v1.ReplayTasksResponse\x12S\n\x12TriggerWorkflowRun\x12\x1d.v1.TriggerWorkflowRunRequest\x1a\x1e.v1.TriggerWorkflowRunResponse\x12\x44\n\rGetRunDetails\x12\x18.v1.GetRunDetailsRequest\x1a\x19.v1.GetRunDetailsResponse\x12P\n\x11\x42ranchDurableTask\x12\x1c.v1.BranchDurableTaskRequest\x1a\x1d.v1.BranchDurableTaskResponseBBZ@github.com/hatchet-dev/hatchet/internal/services/shared/proto/v1b\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -43,14 +43,14 @@ _globals['_CREATETASKOPTS_SLOTREQUESTSENTRY']._serialized_options = b'8\001' _globals['_GETRUNDETAILSRESPONSE_TASKRUNSENTRY']._loaded_options = None _globals['_GETRUNDETAILSRESPONSE_TASKRUNSENTRY']._serialized_options = b'8\001' - _globals['_STICKYSTRATEGY']._serialized_start=3411 - _globals['_STICKYSTRATEGY']._serialized_end=3447 - _globals['_RATELIMITDURATION']._serialized_start=3449 - _globals['_RATELIMITDURATION']._serialized_end=3542 - _globals['_RUNSTATUS']._serialized_start=3544 - _globals['_RUNSTATUS']._serialized_end=3635 - _globals['_CONCURRENCYLIMITSTRATEGY']._serialized_start=3637 - _globals['_CONCURRENCYLIMITSTRATEGY']._serialized_end=3764 + _globals['_STICKYSTRATEGY']._serialized_start=3455 + _globals['_STICKYSTRATEGY']._serialized_end=3491 + _globals['_RATELIMITDURATION']._serialized_start=3493 + _globals['_RATELIMITDURATION']._serialized_end=3586 + _globals['_RUNSTATUS']._serialized_start=3588 + _globals['_RUNSTATUS']._serialized_end=3679 + _globals['_CONCURRENCYLIMITSTRATEGY']._serialized_start=3681 + _globals['_CONCURRENCYLIMITSTRATEGY']._serialized_end=3808 _globals['_CANCELTASKSREQUEST']._serialized_start=111 _globals['_CANCELTASKSREQUEST']._serialized_end=202 _globals['_REPLAYTASKSREQUEST']._serialized_start=204 @@ -62,39 +62,39 @@ _globals['_REPLAYTASKSRESPONSE']._serialized_start=531 _globals['_REPLAYTASKSRESPONSE']._serialized_end=576 _globals['_TRIGGERWORKFLOWRUNREQUEST']._serialized_start=579 - _globals['_TRIGGERWORKFLOWRUNREQUEST']._serialized_end=881 - _globals['_TRIGGERWORKFLOWRUNREQUEST_DESIREDWORKERLABELSENTRY']._serialized_start=785 - _globals['_TRIGGERWORKFLOWRUNREQUEST_DESIREDWORKERLABELSENTRY']._serialized_end=868 - _globals['_TRIGGERWORKFLOWRUNRESPONSE']._serialized_start=883 - _globals['_TRIGGERWORKFLOWRUNRESPONSE']._serialized_end=932 - _globals['_BRANCHDURABLETASKREQUEST']._serialized_start=934 - _globals['_BRANCHDURABLETASKREQUEST']._serialized_end=1022 - _globals['_BRANCHDURABLETASKRESPONSE']._serialized_start=1024 - _globals['_BRANCHDURABLETASKRESPONSE']._serialized_end=1113 - _globals['_CREATEWORKFLOWVERSIONREQUEST']._serialized_start=1116 - _globals['_CREATEWORKFLOWVERSIONREQUEST']._serialized_end=1672 - _globals['_DEFAULTFILTER']._serialized_start=1674 - _globals['_DEFAULTFILTER']._serialized_end=1758 - _globals['_CONCURRENCY']._serialized_start=1761 - _globals['_CONCURRENCY']._serialized_end=1908 - _globals['_CREATETASKOPTS']._serialized_start=1911 - _globals['_CREATETASKOPTS']._serialized_end=2606 - _globals['_CREATETASKOPTS_WORKERLABELSENTRY']._serialized_start=2398 - _globals['_CREATETASKOPTS_WORKERLABELSENTRY']._serialized_end=2474 - _globals['_CREATETASKOPTS_SLOTREQUESTSENTRY']._serialized_start=2476 - _globals['_CREATETASKOPTS_SLOTREQUESTSENTRY']._serialized_end=2527 - _globals['_CREATETASKRATELIMIT']._serialized_start=2609 - _globals['_CREATETASKRATELIMIT']._serialized_end=2862 - _globals['_CREATEWORKFLOWVERSIONRESPONSE']._serialized_start=2864 - _globals['_CREATEWORKFLOWVERSIONRESPONSE']._serialized_end=2928 - _globals['_GETRUNDETAILSREQUEST']._serialized_start=2930 - _globals['_GETRUNDETAILSREQUEST']._serialized_end=2973 - _globals['_TASKRUNDETAIL']._serialized_start=2976 - _globals['_TASKRUNDETAIL']._serialized_end=3146 - _globals['_GETRUNDETAILSRESPONSE']._serialized_start=3149 - _globals['_GETRUNDETAILSRESPONSE']._serialized_end=3409 - _globals['_GETRUNDETAILSRESPONSE_TASKRUNSENTRY']._serialized_start=3343 - _globals['_GETRUNDETAILSRESPONSE_TASKRUNSENTRY']._serialized_end=3409 - _globals['_ADMINSERVICE']._serialized_start=3767 - _globals['_ADMINSERVICE']._serialized_end=4230 + _globals['_TRIGGERWORKFLOWRUNREQUEST']._serialized_end=925 + _globals['_TRIGGERWORKFLOWRUNREQUEST_DESIREDWORKERLABELSENTRY']._serialized_start=812 + _globals['_TRIGGERWORKFLOWRUNREQUEST_DESIREDWORKERLABELSENTRY']._serialized_end=895 + _globals['_TRIGGERWORKFLOWRUNRESPONSE']._serialized_start=927 + _globals['_TRIGGERWORKFLOWRUNRESPONSE']._serialized_end=976 + _globals['_BRANCHDURABLETASKREQUEST']._serialized_start=978 + _globals['_BRANCHDURABLETASKREQUEST']._serialized_end=1066 + _globals['_BRANCHDURABLETASKRESPONSE']._serialized_start=1068 + _globals['_BRANCHDURABLETASKRESPONSE']._serialized_end=1157 + _globals['_CREATEWORKFLOWVERSIONREQUEST']._serialized_start=1160 + _globals['_CREATEWORKFLOWVERSIONREQUEST']._serialized_end=1716 + _globals['_DEFAULTFILTER']._serialized_start=1718 + _globals['_DEFAULTFILTER']._serialized_end=1802 + _globals['_CONCURRENCY']._serialized_start=1805 + _globals['_CONCURRENCY']._serialized_end=1952 + _globals['_CREATETASKOPTS']._serialized_start=1955 + _globals['_CREATETASKOPTS']._serialized_end=2650 + _globals['_CREATETASKOPTS_WORKERLABELSENTRY']._serialized_start=2442 + _globals['_CREATETASKOPTS_WORKERLABELSENTRY']._serialized_end=2518 + _globals['_CREATETASKOPTS_SLOTREQUESTSENTRY']._serialized_start=2520 + _globals['_CREATETASKOPTS_SLOTREQUESTSENTRY']._serialized_end=2571 + _globals['_CREATETASKRATELIMIT']._serialized_start=2653 + _globals['_CREATETASKRATELIMIT']._serialized_end=2906 + _globals['_CREATEWORKFLOWVERSIONRESPONSE']._serialized_start=2908 + _globals['_CREATEWORKFLOWVERSIONRESPONSE']._serialized_end=2972 + _globals['_GETRUNDETAILSREQUEST']._serialized_start=2974 + _globals['_GETRUNDETAILSREQUEST']._serialized_end=3017 + _globals['_TASKRUNDETAIL']._serialized_start=3020 + _globals['_TASKRUNDETAIL']._serialized_end=3190 + _globals['_GETRUNDETAILSRESPONSE']._serialized_start=3193 + _globals['_GETRUNDETAILSRESPONSE']._serialized_end=3453 + _globals['_GETRUNDETAILSRESPONSE_TASKRUNSENTRY']._serialized_start=3387 + _globals['_GETRUNDETAILSRESPONSE_TASKRUNSENTRY']._serialized_end=3453 + _globals['_ADMINSERVICE']._serialized_start=3811 + _globals['_ADMINSERVICE']._serialized_end=4274 # @@protoc_insertion_point(module_scope) diff --git a/sdks/python/hatchet_sdk/contracts/v1/workflows_pb2.pyi b/sdks/python/hatchet_sdk/contracts/v1/workflows_pb2.pyi index 3015f82678..85edd9c325 100644 --- a/sdks/python/hatchet_sdk/contracts/v1/workflows_pb2.pyi +++ b/sdks/python/hatchet_sdk/contracts/v1/workflows_pb2.pyi @@ -107,7 +107,7 @@ class ReplayTasksResponse(_message.Message): def __init__(self, replayed_tasks: _Optional[_Iterable[str]] = ...) -> None: ... class TriggerWorkflowRunRequest(_message.Message): - __slots__ = ("workflow_name", "input", "additional_metadata", "priority", "desired_worker_labels") + __slots__ = ("workflow_name", "input", "additional_metadata", "priority", "desired_worker_labels", "display_name") class DesiredWorkerLabelsEntry(_message.Message): __slots__ = ("key", "value") KEY_FIELD_NUMBER: _ClassVar[int] @@ -120,12 +120,14 @@ class TriggerWorkflowRunRequest(_message.Message): ADDITIONAL_METADATA_FIELD_NUMBER: _ClassVar[int] PRIORITY_FIELD_NUMBER: _ClassVar[int] DESIRED_WORKER_LABELS_FIELD_NUMBER: _ClassVar[int] + DISPLAY_NAME_FIELD_NUMBER: _ClassVar[int] workflow_name: str input: bytes additional_metadata: bytes priority: int desired_worker_labels: _containers.MessageMap[str, _trigger_pb2.DesiredWorkerLabels] - def __init__(self, workflow_name: _Optional[str] = ..., input: _Optional[bytes] = ..., additional_metadata: _Optional[bytes] = ..., priority: _Optional[int] = ..., desired_worker_labels: _Optional[_Mapping[str, _trigger_pb2.DesiredWorkerLabels]] = ...) -> None: ... + display_name: str + def __init__(self, workflow_name: _Optional[str] = ..., input: _Optional[bytes] = ..., additional_metadata: _Optional[bytes] = ..., priority: _Optional[int] = ..., desired_worker_labels: _Optional[_Mapping[str, _trigger_pb2.DesiredWorkerLabels]] = ..., display_name: _Optional[str] = ...) -> None: ... class TriggerWorkflowRunResponse(_message.Message): __slots__ = ("external_id",) @@ -251,7 +253,7 @@ class CreateTaskOpts(_message.Message): schedule_timeout: str is_durable: bool slot_requests: _containers.ScalarMap[str, int] - def __init__(self, readable_id: _Optional[str] = ..., action: _Optional[str] = ..., timeout: _Optional[str] = ..., inputs: _Optional[str] = ..., parents: _Optional[_Iterable[str]] = ..., retries: _Optional[int] = ..., rate_limits: _Optional[_Iterable[_Union[CreateTaskRateLimit, _Mapping]]] = ..., worker_labels: _Optional[_Mapping[str, _trigger_pb2.DesiredWorkerLabels]] = ..., backoff_factor: _Optional[float] = ..., backoff_max_seconds: _Optional[int] = ..., concurrency: _Optional[_Iterable[_Union[Concurrency, _Mapping]]] = ..., conditions: _Optional[_Union[_condition_pb2.TaskConditions, _Mapping]] = ..., schedule_timeout: _Optional[str] = ..., is_durable: bool = ..., slot_requests: _Optional[_Mapping[str, int]] = ...) -> None: ... + def __init__(self, readable_id: _Optional[str] = ..., action: _Optional[str] = ..., timeout: _Optional[str] = ..., inputs: _Optional[str] = ..., parents: _Optional[_Iterable[str]] = ..., retries: _Optional[int] = ..., rate_limits: _Optional[_Iterable[_Union[CreateTaskRateLimit, _Mapping]]] = ..., worker_labels: _Optional[_Mapping[str, _trigger_pb2.DesiredWorkerLabels]] = ..., backoff_factor: _Optional[float] = ..., backoff_max_seconds: _Optional[int] = ..., concurrency: _Optional[_Iterable[_Union[Concurrency, _Mapping]]] = ..., conditions: _Optional[_Union[_condition_pb2.TaskConditions, _Mapping]] = ..., schedule_timeout: _Optional[str] = ..., is_durable: _Optional[bool] = ..., slot_requests: _Optional[_Mapping[str, int]] = ...) -> None: ... class CreateTaskRateLimit(_message.Message): __slots__ = ("key", "units", "key_expr", "units_expr", "limit_values_expr", "duration") @@ -297,7 +299,7 @@ class TaskRunDetail(_message.Message): output: bytes readable_id: str is_evicted: bool - def __init__(self, external_id: _Optional[str] = ..., status: _Optional[_Union[RunStatus, str]] = ..., error: _Optional[str] = ..., output: _Optional[bytes] = ..., readable_id: _Optional[str] = ..., is_evicted: bool = ...) -> None: ... + def __init__(self, external_id: _Optional[str] = ..., status: _Optional[_Union[RunStatus, str]] = ..., error: _Optional[str] = ..., output: _Optional[bytes] = ..., readable_id: _Optional[str] = ..., is_evicted: _Optional[bool] = ...) -> None: ... class GetRunDetailsResponse(_message.Message): __slots__ = ("input", "status", "task_runs", "done", "additional_metadata", "is_evicted") @@ -320,4 +322,4 @@ class GetRunDetailsResponse(_message.Message): done: bool additional_metadata: bytes is_evicted: bool - def __init__(self, input: _Optional[bytes] = ..., status: _Optional[_Union[RunStatus, str]] = ..., task_runs: _Optional[_Mapping[str, TaskRunDetail]] = ..., done: bool = ..., additional_metadata: _Optional[bytes] = ..., is_evicted: bool = ...) -> None: ... + def __init__(self, input: _Optional[bytes] = ..., status: _Optional[_Union[RunStatus, str]] = ..., task_runs: _Optional[_Mapping[str, TaskRunDetail]] = ..., done: _Optional[bool] = ..., additional_metadata: _Optional[bytes] = ..., is_evicted: _Optional[bool] = ...) -> None: ... diff --git a/sdks/python/hatchet_sdk/runnables/workflow.py b/sdks/python/hatchet_sdk/runnables/workflow.py index 56966f5faf..788e343e06 100644 --- a/sdks/python/hatchet_sdk/runnables/workflow.py +++ b/sdks/python/hatchet_sdk/runnables/workflow.py @@ -291,6 +291,7 @@ def _create_trigger_run_options_with_combined_additional_meta( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> TriggerWorkflowOptions: if options is not None: warn( @@ -306,6 +307,7 @@ def _create_trigger_run_options_with_combined_additional_meta( sticky=sticky, desired_worker_id=desired_worker_id, desired_worker_label=desired_worker_labels, + display_name=display_name, ) options_copy = options.model_copy() options_copy.additional_metadata = self._combine_additional_metadata( @@ -381,6 +383,7 @@ def create_bulk_run_item( desired_worker_id: str | None = None, sticky: bool = False, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> WorkflowRunTriggerConfig: """ Create a bulk run item for the workflow. This is intended to be used in conjunction with the various `run_many` methods. @@ -408,6 +411,7 @@ def create_bulk_run_item( sticky=sticky, desired_worker_id=desired_worker_id, desired_worker_labels=desired_worker_labels, + display_name=display_name, ), key=key, ) @@ -866,6 +870,7 @@ def run_no_wait( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> WorkflowRunRef: """ Synchronously trigger a workflow run without waiting for it to complete. @@ -897,6 +902,7 @@ def run_no_wait( child_key=child_key, additional_metadata=additional_metadata, priority=priority, + display_name=display_name, sticky=sticky, desired_worker_id=desired_worker_id, desired_worker_labels=desired_worker_labels, @@ -914,6 +920,7 @@ def run( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> dict[str, Any]: ... @overload @@ -929,6 +936,7 @@ def run( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> WorkflowRunRef: ... def run( @@ -942,6 +950,7 @@ def run( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> WorkflowRunRef | dict[str, Any]: """ Run the workflow synchronously and wait for it to complete. @@ -972,6 +981,7 @@ def run( sticky=sticky, desired_worker_id=desired_worker_id, desired_worker_labels=desired_worker_labels, + display_name=display_name, ), ) @@ -990,6 +1000,7 @@ async def aio_run_no_wait( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> WorkflowRunRef: """ Asynchronously trigger a workflow run without waiting for it to complete. @@ -1021,6 +1032,7 @@ async def aio_run_no_wait( child_key=child_key, additional_metadata=additional_metadata, priority=priority, + display_name=display_name, sticky=sticky, desired_worker_id=desired_worker_id, desired_worker_labels=desired_worker_labels, @@ -1038,6 +1050,7 @@ async def aio_run( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> dict[str, Any]: ... @overload @@ -1053,6 +1066,7 @@ async def aio_run( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> WorkflowRunRef: ... async def aio_run( @@ -1066,6 +1080,7 @@ async def aio_run( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> WorkflowRunRef | dict[str, Any]: """ Run the workflow asynchronously and wait for it to complete. @@ -1093,6 +1108,7 @@ async def aio_run( additional_metadata=additional_metadata, priority=priority, sticky=sticky, + display_name=display_name, desired_worker_id=desired_worker_id, desired_worker_labels=desired_worker_labels, ) @@ -1822,6 +1838,7 @@ def run( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> R: ... @overload @@ -1837,6 +1854,7 @@ def run( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> TaskRunRef[TWorkflowInput, R]: ... def run( @@ -1850,6 +1868,7 @@ def run( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> TaskRunRef[TWorkflowInput, R] | R: """ Run the workflow synchronously and wait for it to complete. @@ -1876,6 +1895,7 @@ def run( child_key=child_key, additional_metadata=additional_metadata, priority=priority, + display_name=display_name, sticky=sticky, desired_worker_id=desired_worker_id, desired_worker_labels=desired_worker_labels, @@ -1890,6 +1910,7 @@ def run( child_key=child_key, additional_metadata=additional_metadata, priority=priority, + display_name=display_name, sticky=sticky, desired_worker_id=desired_worker_id, desired_worker_labels=desired_worker_labels, @@ -1908,6 +1929,7 @@ async def aio_run( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> R: ... @overload @@ -1923,6 +1945,7 @@ async def aio_run( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> TaskRunRef[TWorkflowInput, R]: ... async def aio_run( @@ -1936,6 +1959,7 @@ async def aio_run( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> TaskRunRef[TWorkflowInput, R] | R: """ Run the workflow asynchronously and wait for it to complete. @@ -1963,6 +1987,7 @@ async def aio_run( child_key=child_key, additional_metadata=additional_metadata, priority=priority, + display_name=display_name, sticky=sticky, desired_worker_id=desired_worker_id, desired_worker_labels=desired_worker_labels, @@ -1977,6 +2002,7 @@ async def aio_run( child_key=child_key, additional_metadata=additional_metadata, priority=priority, + display_name=display_name, sticky=sticky, desired_worker_id=desired_worker_id, desired_worker_labels=desired_worker_labels, @@ -1993,6 +2019,7 @@ def run_no_wait( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> TaskRunRef[TWorkflowInput, R]: """ Trigger a workflow run without waiting for it to complete. @@ -2025,6 +2052,7 @@ def run_no_wait( child_key=child_key, additional_metadata=additional_metadata, priority=priority, + display_name=display_name, sticky=sticky, desired_worker_id=desired_worker_id, desired_worker_labels=desired_worker_labels, @@ -2040,6 +2068,7 @@ async def aio_run_no_wait( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> TaskRunRef[TWorkflowInput, R]: """ Asynchronously trigger a workflow run without waiting for it to complete. @@ -2071,6 +2100,7 @@ async def aio_run_no_wait( child_key=child_key, additional_metadata=additional_metadata, priority=priority, + display_name=display_name, sticky=sticky, desired_worker_id=desired_worker_id, desired_worker_labels=desired_worker_labels, diff --git a/sdks/python/hatchet_sdk/types/trigger.py b/sdks/python/hatchet_sdk/types/trigger.py index 5ddbbb58dd..373d6aaf21 100644 --- a/sdks/python/hatchet_sdk/types/trigger.py +++ b/sdks/python/hatchet_sdk/types/trigger.py @@ -24,6 +24,7 @@ class TriggerWorkflowOptions(ScheduleTriggerWorkflowOptions): desired_worker_label: ( dict[str, DesiredWorkerLabel] | list[DesiredWorkerLabel] | None ) = None + display_name: str | None = None class WorkflowRunTriggerConfig(BaseModel): diff --git a/sdks/python/tests/unit/test_trigger_display_name.py b/sdks/python/tests/unit/test_trigger_display_name.py new file mode 100644 index 0000000000..1473ff5977 --- /dev/null +++ b/sdks/python/tests/unit/test_trigger_display_name.py @@ -0,0 +1,73 @@ +from types import SimpleNamespace + +from hatchet_sdk.clients.admin import AdminClient +from hatchet_sdk.runnables.workflow import BaseWorkflow +from hatchet_sdk.types.trigger import TriggerWorkflowOptions + + +def _admin() -> AdminClient: + # _prepare_workflow_request only uses the nested TriggerWorkflowRequest class + # attribute, so we can bypass connection setup. + return object.__new__(AdminClient) + + +def _admin_for_run() -> AdminClient: + # _create_workflow_run_request additionally reads self.namespace and + # self.config.apply_namespace; everything else comes from contextvars that + # default to None. Stub just those two so we can drive the real request path. + admin = object.__new__(AdminClient) + admin.namespace = "" + admin.config = SimpleNamespace(apply_namespace=lambda name, _ns: name) # type: ignore[assignment] + return admin + + +def test_prepare_workflow_request_maps_display_name() -> None: + req = _admin()._prepare_workflow_request( + "my-workflow", "{}", TriggerWorkflowOptions(display_name="Acme Corp") + ) + + assert req.HasField("display_name") + assert req.display_name == "Acme Corp" + + +def test_prepare_workflow_request_omits_display_name_when_unset() -> None: + req = _admin()._prepare_workflow_request( + "my-workflow", "{}", TriggerWorkflowOptions() + ) + + assert not req.HasField("display_name") + + +def test_create_workflow_run_request_sends_display_name() -> None: + # Regression guard: every public run surface (run/run_no_wait/aio_* and bulk) + # and durable child spawns build their gRPC request via + # _create_workflow_run_request, which reconstructs TriggerWorkflowOptions. + # display_name must survive that reconstruction and reach the protobuf. + req = _admin_for_run()._create_workflow_run_request( + "my-workflow", "{}", TriggerWorkflowOptions(display_name="Acme Corp") + ) + + assert req.HasField("display_name") + assert req.display_name == "Acme Corp" + + +def test_create_workflow_run_request_omits_display_name_when_unset() -> None: + req = _admin_for_run()._create_workflow_run_request( + "my-workflow", "{}", TriggerWorkflowOptions() + ) + + assert not req.HasField("display_name") + + +def test_direct_display_name_kwarg_flows_through_run_options() -> None: + # The modern run()/run_many() API passes display_name as a direct keyword + # argument (not via the deprecated `options` object). This is the shared funnel + # every run surface routes through. + workflow = object.__new__(BaseWorkflow) + workflow._config = SimpleNamespace(default_additional_metadata={}) # type: ignore[assignment] + + options = workflow._create_trigger_run_options_with_combined_additional_meta( + None, display_name="Acme Corp" + ) + + assert options.display_name == "Acme Corp" diff --git a/sdks/ruby/src/CHANGELOG.md b/sdks/ruby/src/CHANGELOG.md index 34a2fba4f7..b013050f3e 100644 --- a/sdks/ruby/src/CHANGELOG.md +++ b/sdks/ruby/src/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to Hatchet's Ruby SDK will be documented in this changelog. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Added + +- Added a `display_name` option to set a custom, human-readable name on a run at trigger time, supported by both `trigger_workflow` and `bulk_trigger_workflow` (per-item) and available on `TriggerWorkflowOptions`. Single-task runs carry the name on the task; multi-step DAG runs carry it on the DAG (the DAG's step tasks keep their generated names). Empty or whitespace-only values fall back to the generated `-` name, and names longer than 255 characters are stored truncated rather than rejected ([#4259](https://github.com/hatchet-dev/hatchet/issues/4259)). + ## [0.3.1] - 2026-06-12 ### Fixed diff --git a/sdks/ruby/src/lib/hatchet/clients/grpc/admin.rb b/sdks/ruby/src/lib/hatchet/clients/grpc/admin.rb index 4c78f120cc..6edc8c84fb 100644 --- a/sdks/ruby/src/lib/hatchet/clients/grpc/admin.rb +++ b/sdks/ruby/src/lib/hatchet/clients/grpc/admin.rb @@ -74,6 +74,7 @@ def trigger_workflow(workflow_name, input: {}, options: {}) request_args[:child_key] = options[:child_key] if options[:child_key] request_args[:desired_worker_id] = options[:desired_worker_id] if options[:desired_worker_id] request_args[:priority] = options[:priority] if options[:priority] + request_args[:display_name] = options[:display_name] if options[:display_name] if options[:additional_metadata] request_args[:additional_metadata] = if options[:additional_metadata].is_a?(String) @@ -128,6 +129,7 @@ def bulk_trigger_workflow(workflow_name, items) request_args[:child_key] = opts[:child_key] if opts[:child_key] request_args[:desired_worker_id] = opts[:desired_worker_id] if opts[:desired_worker_id] request_args[:priority] = opts[:priority] if opts[:priority] + request_args[:display_name] = opts[:display_name] if opts[:display_name] if opts[:additional_metadata] request_args[:additional_metadata] = if opts[:additional_metadata].is_a?(String) diff --git a/sdks/ruby/src/lib/hatchet/contracts/v1/shared/trigger_pb.rb b/sdks/ruby/src/lib/hatchet/contracts/v1/shared/trigger_pb.rb index a4582ee990..480bb90736 100644 --- a/sdks/ruby/src/lib/hatchet/contracts/v1/shared/trigger_pb.rb +++ b/sdks/ruby/src/lib/hatchet/contracts/v1/shared/trigger_pb.rb @@ -5,7 +5,7 @@ require 'google/protobuf' -descriptor_data = "\n\x17v1/shared/trigger.proto\x12\x02v1\"\xe8\x01\n\x13\x44\x65siredWorkerLabels\x12\x16\n\tstr_value\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x16\n\tint_value\x18\x02 \x01(\x05H\x01\x88\x01\x01\x12\x15\n\x08required\x18\x03 \x01(\x08H\x02\x88\x01\x01\x12\x32\n\ncomparator\x18\x04 \x01(\x0e\x32\x19.v1.WorkerLabelComparatorH\x03\x88\x01\x01\x12\x13\n\x06weight\x18\x05 \x01(\x05H\x04\x88\x01\x01\x42\x0c\n\n_str_valueB\x0c\n\n_int_valueB\x0b\n\t_requiredB\r\n\x0b_comparatorB\t\n\x07_weight\"\xb2\x04\n\x16TriggerWorkflowRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05input\x18\x02 \x01(\t\x12\x16\n\tparent_id\x18\x03 \x01(\tH\x00\x88\x01\x01\x12(\n\x1bparent_task_run_external_id\x18\x04 \x01(\tH\x01\x88\x01\x01\x12\x18\n\x0b\x63hild_index\x18\x05 \x01(\x05H\x02\x88\x01\x01\x12\x16\n\tchild_key\x18\x06 \x01(\tH\x03\x88\x01\x01\x12 \n\x13\x61\x64\x64itional_metadata\x18\x07 \x01(\tH\x04\x88\x01\x01\x12\x1e\n\x11\x64\x65sired_worker_id\x18\x08 \x01(\tH\x05\x88\x01\x01\x12\x15\n\x08priority\x18\t \x01(\x05H\x06\x88\x01\x01\x12R\n\x15\x64\x65sired_worker_labels\x18\n \x03(\x0b\x32\x33.v1.TriggerWorkflowRequest.DesiredWorkerLabelsEntry\x1aS\n\x18\x44\x65siredWorkerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.v1.DesiredWorkerLabels:\x02\x38\x01\x42\x0c\n\n_parent_idB\x1e\n\x1c_parent_task_run_external_idB\x0e\n\x0c_child_indexB\x0c\n\n_child_keyB\x16\n\x14_additional_metadataB\x14\n\x12_desired_worker_idB\x0b\n\t_priority*\x85\x01\n\x15WorkerLabelComparator\x12\t\n\x05\x45QUAL\x10\x00\x12\r\n\tNOT_EQUAL\x10\x01\x12\x10\n\x0cGREATER_THAN\x10\x02\x12\x19\n\x15GREATER_THAN_OR_EQUAL\x10\x03\x12\r\n\tLESS_THAN\x10\x04\x12\x16\n\x12LESS_THAN_OR_EQUAL\x10\x05\x42\x42Z@github.com/hatchet-dev/hatchet/internal/services/shared/proto/v1b\x06proto3" +descriptor_data = "\n\x17v1/shared/trigger.proto\x12\x02v1\"\xe8\x01\n\x13\x44\x65siredWorkerLabels\x12\x16\n\tstr_value\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x16\n\tint_value\x18\x02 \x01(\x05H\x01\x88\x01\x01\x12\x15\n\x08required\x18\x03 \x01(\x08H\x02\x88\x01\x01\x12\x32\n\ncomparator\x18\x04 \x01(\x0e\x32\x19.v1.WorkerLabelComparatorH\x03\x88\x01\x01\x12\x13\n\x06weight\x18\x05 \x01(\x05H\x04\x88\x01\x01\x42\x0c\n\n_str_valueB\x0c\n\n_int_valueB\x0b\n\t_requiredB\r\n\x0b_comparatorB\t\n\x07_weight\"\xde\x04\n\x16TriggerWorkflowRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05input\x18\x02 \x01(\t\x12\x16\n\tparent_id\x18\x03 \x01(\tH\x00\x88\x01\x01\x12(\n\x1bparent_task_run_external_id\x18\x04 \x01(\tH\x01\x88\x01\x01\x12\x18\n\x0b\x63hild_index\x18\x05 \x01(\x05H\x02\x88\x01\x01\x12\x16\n\tchild_key\x18\x06 \x01(\tH\x03\x88\x01\x01\x12 \n\x13\x61\x64\x64itional_metadata\x18\x07 \x01(\tH\x04\x88\x01\x01\x12\x1e\n\x11\x64\x65sired_worker_id\x18\x08 \x01(\tH\x05\x88\x01\x01\x12\x15\n\x08priority\x18\t \x01(\x05H\x06\x88\x01\x01\x12R\n\x15\x64\x65sired_worker_labels\x18\n \x03(\x0b\x32\x33.v1.TriggerWorkflowRequest.DesiredWorkerLabelsEntry\x12\x19\n\x0c\x64isplay_name\x18\x0b \x01(\tH\x07\x88\x01\x01\x1aS\n\x18\x44\x65siredWorkerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.v1.DesiredWorkerLabels:\x02\x38\x01\x42\x0c\n\n_parent_idB\x1e\n\x1c_parent_task_run_external_idB\x0e\n\x0c_child_indexB\x0c\n\n_child_keyB\x16\n\x14_additional_metadataB\x14\n\x12_desired_worker_idB\x0b\n\t_priorityB\x0f\n\r_display_name*\x85\x01\n\x15WorkerLabelComparator\x12\t\n\x05\x45QUAL\x10\x00\x12\r\n\tNOT_EQUAL\x10\x01\x12\x10\n\x0cGREATER_THAN\x10\x02\x12\x19\n\x15GREATER_THAN_OR_EQUAL\x10\x03\x12\r\n\tLESS_THAN\x10\x04\x12\x16\n\x12LESS_THAN_OR_EQUAL\x10\x05\x42\x42Z@github.com/hatchet-dev/hatchet/internal/services/shared/proto/v1b\x06proto3" pool = ::Google::Protobuf::DescriptorPool.generated_pool pool.add_serialized_file(descriptor_data) diff --git a/sdks/ruby/src/lib/hatchet/contracts/v1/workflows_pb.rb b/sdks/ruby/src/lib/hatchet/contracts/v1/workflows_pb.rb index 628b311eea..3e976c2df3 100644 --- a/sdks/ruby/src/lib/hatchet/contracts/v1/workflows_pb.rb +++ b/sdks/ruby/src/lib/hatchet/contracts/v1/workflows_pb.rb @@ -9,7 +9,7 @@ require 'v1/shared/trigger_pb' -descriptor_data = "\n\x12v1/workflows.proto\x12\x02v1\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x19v1/shared/condition.proto\x1a\x17v1/shared/trigger.proto\"[\n\x12\x43\x61ncelTasksRequest\x12\x14\n\x0c\x65xternal_ids\x18\x01 \x03(\t\x12$\n\x06\x66ilter\x18\x02 \x01(\x0b\x32\x0f.v1.TasksFilterH\x00\x88\x01\x01\x42\t\n\x07_filter\"[\n\x12ReplayTasksRequest\x12\x14\n\x0c\x65xternal_ids\x18\x01 \x03(\t\x12$\n\x06\x66ilter\x18\x02 \x01(\x0b\x32\x0f.v1.TasksFilterH\x00\x88\x01\x01\x42\t\n\x07_filter\"\xb7\x01\n\x0bTasksFilter\x12\x10\n\x08statuses\x18\x01 \x03(\t\x12)\n\x05since\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\x05until\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x88\x01\x01\x12\x14\n\x0cworkflow_ids\x18\x04 \x03(\t\x12\x1b\n\x13\x61\x64\x64itional_metadata\x18\x05 \x03(\tB\x08\n\x06_until\".\n\x13\x43\x61ncelTasksResponse\x12\x17\n\x0f\x63\x61ncelled_tasks\x18\x01 \x03(\t\"-\n\x13ReplayTasksResponse\x12\x16\n\x0ereplayed_tasks\x18\x01 \x03(\t\"\xae\x02\n\x19TriggerWorkflowRunRequest\x12\x15\n\rworkflow_name\x18\x01 \x01(\t\x12\r\n\x05input\x18\x02 \x01(\x0c\x12\x1b\n\x13\x61\x64\x64itional_metadata\x18\x03 \x01(\x0c\x12\x15\n\x08priority\x18\x04 \x01(\x05H\x00\x88\x01\x01\x12U\n\x15\x64\x65sired_worker_labels\x18\x05 \x03(\x0b\x32\x36.v1.TriggerWorkflowRunRequest.DesiredWorkerLabelsEntry\x1aS\n\x18\x44\x65siredWorkerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.v1.DesiredWorkerLabels:\x02\x38\x01\x42\x0b\n\t_priority\"1\n\x1aTriggerWorkflowRunResponse\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\"X\n\x18\x42ranchDurableTaskRequest\x12\x18\n\x10task_external_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\x03\x12\x11\n\tbranch_id\x18\x03 \x01(\x03\"Y\n\x19\x42ranchDurableTaskResponse\x12\x18\n\x10task_external_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\x03\x12\x11\n\tbranch_id\x18\x03 \x01(\x03\"\xac\x04\n\x1c\x43reateWorkflowVersionRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x0f\n\x07version\x18\x03 \x01(\t\x12\x16\n\x0e\x65vent_triggers\x18\x04 \x03(\t\x12\x15\n\rcron_triggers\x18\x05 \x03(\t\x12!\n\x05tasks\x18\x06 \x03(\x0b\x32\x12.v1.CreateTaskOpts\x12$\n\x0b\x63oncurrency\x18\x07 \x01(\x0b\x32\x0f.v1.Concurrency\x12\x17\n\ncron_input\x18\x08 \x01(\tH\x00\x88\x01\x01\x12\x30\n\x0fon_failure_task\x18\t \x01(\x0b\x32\x12.v1.CreateTaskOptsH\x01\x88\x01\x01\x12\'\n\x06sticky\x18\n \x01(\x0e\x32\x12.v1.StickyStrategyH\x02\x88\x01\x01\x12\x1d\n\x10\x64\x65\x66\x61ult_priority\x18\x0b \x01(\x05H\x03\x88\x01\x01\x12(\n\x0f\x63oncurrency_arr\x18\x0c \x03(\x0b\x32\x0f.v1.Concurrency\x12*\n\x0f\x64\x65\x66\x61ult_filters\x18\r \x03(\x0b\x32\x11.v1.DefaultFilter\x12\x1e\n\x11input_json_schema\x18\x0e \x01(\x0cH\x04\x88\x01\x01\x42\r\n\x0b_cron_inputB\x12\n\x10_on_failure_taskB\t\n\x07_stickyB\x13\n\x11_default_priorityB\x14\n\x12_input_json_schema\"T\n\rDefaultFilter\x12\x12\n\nexpression\x18\x01 \x01(\t\x12\r\n\x05scope\x18\x02 \x01(\t\x12\x14\n\x07payload\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x42\n\n\x08_payload\"\x93\x01\n\x0b\x43oncurrency\x12\x12\n\nexpression\x18\x01 \x01(\t\x12\x15\n\x08max_runs\x18\x02 \x01(\x05H\x00\x88\x01\x01\x12\x39\n\x0elimit_strategy\x18\x03 \x01(\x0e\x32\x1c.v1.ConcurrencyLimitStrategyH\x01\x88\x01\x01\x42\x0b\n\t_max_runsB\x11\n\x0f_limit_strategy\"\xb7\x05\n\x0e\x43reateTaskOpts\x12\x13\n\x0breadable_id\x18\x01 \x01(\t\x12\x0e\n\x06\x61\x63tion\x18\x02 \x01(\t\x12\x0f\n\x07timeout\x18\x03 \x01(\t\x12\x0e\n\x06inputs\x18\x04 \x01(\t\x12\x0f\n\x07parents\x18\x05 \x03(\t\x12\x0f\n\x07retries\x18\x06 \x01(\x05\x12,\n\x0brate_limits\x18\x07 \x03(\x0b\x32\x17.v1.CreateTaskRateLimit\x12;\n\rworker_labels\x18\x08 \x03(\x0b\x32$.v1.CreateTaskOpts.WorkerLabelsEntry\x12\x1b\n\x0e\x62\x61\x63koff_factor\x18\t \x01(\x02H\x00\x88\x01\x01\x12 \n\x13\x62\x61\x63koff_max_seconds\x18\n \x01(\x05H\x01\x88\x01\x01\x12$\n\x0b\x63oncurrency\x18\x0b \x03(\x0b\x32\x0f.v1.Concurrency\x12+\n\nconditions\x18\x0c \x01(\x0b\x32\x12.v1.TaskConditionsH\x02\x88\x01\x01\x12\x1d\n\x10schedule_timeout\x18\r \x01(\tH\x03\x88\x01\x01\x12\x12\n\nis_durable\x18\x0e \x01(\x08\x12;\n\rslot_requests\x18\x0f \x03(\x0b\x32$.v1.CreateTaskOpts.SlotRequestsEntry\x1aL\n\x11WorkerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.v1.DesiredWorkerLabels:\x02\x38\x01\x1a\x33\n\x11SlotRequestsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x42\x11\n\x0f_backoff_factorB\x16\n\x14_backoff_max_secondsB\r\n\x0b_conditionsB\x13\n\x11_schedule_timeout\"\xfd\x01\n\x13\x43reateTaskRateLimit\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x12\n\x05units\x18\x02 \x01(\x05H\x00\x88\x01\x01\x12\x15\n\x08key_expr\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x17\n\nunits_expr\x18\x04 \x01(\tH\x02\x88\x01\x01\x12\x1e\n\x11limit_values_expr\x18\x05 \x01(\tH\x03\x88\x01\x01\x12,\n\x08\x64uration\x18\x06 \x01(\x0e\x32\x15.v1.RateLimitDurationH\x04\x88\x01\x01\x42\x08\n\x06_unitsB\x0b\n\t_key_exprB\r\n\x0b_units_exprB\x14\n\x12_limit_values_exprB\x0b\n\t_duration\"@\n\x1d\x43reateWorkflowVersionResponse\x12\n\n\x02id\x18\x01 \x01(\t\x12\x13\n\x0bworkflow_id\x18\x02 \x01(\t\"+\n\x14GetRunDetailsRequest\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\"\xaa\x01\n\rTaskRunDetail\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\x12\x1d\n\x06status\x18\x02 \x01(\x0e\x32\r.v1.RunStatus\x12\x12\n\x05\x65rror\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06output\x18\x04 \x01(\x0cH\x01\x88\x01\x01\x12\x13\n\x0breadable_id\x18\x05 \x01(\t\x12\x12\n\nis_evicted\x18\x06 \x01(\x08\x42\x08\n\x06_errorB\t\n\x07_output\"\x84\x02\n\x15GetRunDetailsResponse\x12\r\n\x05input\x18\x01 \x01(\x0c\x12\x1d\n\x06status\x18\x02 \x01(\x0e\x32\r.v1.RunStatus\x12:\n\ttask_runs\x18\x03 \x03(\x0b\x32\'.v1.GetRunDetailsResponse.TaskRunsEntry\x12\x0c\n\x04\x64one\x18\x04 \x01(\x08\x12\x1b\n\x13\x61\x64\x64itional_metadata\x18\x05 \x01(\x0c\x12\x12\n\nis_evicted\x18\x06 \x01(\x08\x1a\x42\n\rTaskRunsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12 \n\x05value\x18\x02 \x01(\x0b\x32\x11.v1.TaskRunDetail:\x02\x38\x01*$\n\x0eStickyStrategy\x12\x08\n\x04SOFT\x10\x00\x12\x08\n\x04HARD\x10\x01*]\n\x11RateLimitDuration\x12\n\n\x06SECOND\x10\x00\x12\n\n\x06MINUTE\x10\x01\x12\x08\n\x04HOUR\x10\x02\x12\x07\n\x03\x44\x41Y\x10\x03\x12\x08\n\x04WEEK\x10\x04\x12\t\n\x05MONTH\x10\x05\x12\x08\n\x04YEAR\x10\x06*[\n\tRunStatus\x12\n\n\x06QUEUED\x10\x00\x12\x0b\n\x07RUNNING\x10\x01\x12\r\n\tCOMPLETED\x10\x02\x12\n\n\x06\x46\x41ILED\x10\x03\x12\r\n\tCANCELLED\x10\x04\x12\x0b\n\x07\x45VICTED\x10\x05*\x7f\n\x18\x43oncurrencyLimitStrategy\x12\x16\n\x12\x43\x41NCEL_IN_PROGRESS\x10\x00\x12\x0f\n\x0b\x44ROP_NEWEST\x10\x01\x12\x10\n\x0cQUEUE_NEWEST\x10\x02\x12\x15\n\x11GROUP_ROUND_ROBIN\x10\x03\x12\x11\n\rCANCEL_NEWEST\x10\x04\x32\xcf\x03\n\x0c\x41\x64minService\x12R\n\x0bPutWorkflow\x12 .v1.CreateWorkflowVersionRequest\x1a!.v1.CreateWorkflowVersionResponse\x12>\n\x0b\x43\x61ncelTasks\x12\x16.v1.CancelTasksRequest\x1a\x17.v1.CancelTasksResponse\x12>\n\x0bReplayTasks\x12\x16.v1.ReplayTasksRequest\x1a\x17.v1.ReplayTasksResponse\x12S\n\x12TriggerWorkflowRun\x12\x1d.v1.TriggerWorkflowRunRequest\x1a\x1e.v1.TriggerWorkflowRunResponse\x12\x44\n\rGetRunDetails\x12\x18.v1.GetRunDetailsRequest\x1a\x19.v1.GetRunDetailsResponse\x12P\n\x11\x42ranchDurableTask\x12\x1c.v1.BranchDurableTaskRequest\x1a\x1d.v1.BranchDurableTaskResponseBBZ@github.com/hatchet-dev/hatchet/internal/services/shared/proto/v1b\x06proto3" +descriptor_data = "\n\x12v1/workflows.proto\x12\x02v1\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x19v1/shared/condition.proto\x1a\x17v1/shared/trigger.proto\"[\n\x12\x43\x61ncelTasksRequest\x12\x14\n\x0c\x65xternal_ids\x18\x01 \x03(\t\x12$\n\x06\x66ilter\x18\x02 \x01(\x0b\x32\x0f.v1.TasksFilterH\x00\x88\x01\x01\x42\t\n\x07_filter\"[\n\x12ReplayTasksRequest\x12\x14\n\x0c\x65xternal_ids\x18\x01 \x03(\t\x12$\n\x06\x66ilter\x18\x02 \x01(\x0b\x32\x0f.v1.TasksFilterH\x00\x88\x01\x01\x42\t\n\x07_filter\"\xb7\x01\n\x0bTasksFilter\x12\x10\n\x08statuses\x18\x01 \x03(\t\x12)\n\x05since\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\x05until\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x88\x01\x01\x12\x14\n\x0cworkflow_ids\x18\x04 \x03(\t\x12\x1b\n\x13\x61\x64\x64itional_metadata\x18\x05 \x03(\tB\x08\n\x06_until\".\n\x13\x43\x61ncelTasksResponse\x12\x17\n\x0f\x63\x61ncelled_tasks\x18\x01 \x03(\t\"-\n\x13ReplayTasksResponse\x12\x16\n\x0ereplayed_tasks\x18\x01 \x03(\t\"\xda\x02\n\x19TriggerWorkflowRunRequest\x12\x15\n\rworkflow_name\x18\x01 \x01(\t\x12\r\n\x05input\x18\x02 \x01(\x0c\x12\x1b\n\x13\x61\x64\x64itional_metadata\x18\x03 \x01(\x0c\x12\x15\n\x08priority\x18\x04 \x01(\x05H\x00\x88\x01\x01\x12U\n\x15\x64\x65sired_worker_labels\x18\x05 \x03(\x0b\x32\x36.v1.TriggerWorkflowRunRequest.DesiredWorkerLabelsEntry\x12\x19\n\x0c\x64isplay_name\x18\x06 \x01(\tH\x01\x88\x01\x01\x1aS\n\x18\x44\x65siredWorkerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.v1.DesiredWorkerLabels:\x02\x38\x01\x42\x0b\n\t_priorityB\x0f\n\r_display_name\"1\n\x1aTriggerWorkflowRunResponse\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\"X\n\x18\x42ranchDurableTaskRequest\x12\x18\n\x10task_external_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\x03\x12\x11\n\tbranch_id\x18\x03 \x01(\x03\"Y\n\x19\x42ranchDurableTaskResponse\x12\x18\n\x10task_external_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\x03\x12\x11\n\tbranch_id\x18\x03 \x01(\x03\"\xac\x04\n\x1c\x43reateWorkflowVersionRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x0f\n\x07version\x18\x03 \x01(\t\x12\x16\n\x0e\x65vent_triggers\x18\x04 \x03(\t\x12\x15\n\rcron_triggers\x18\x05 \x03(\t\x12!\n\x05tasks\x18\x06 \x03(\x0b\x32\x12.v1.CreateTaskOpts\x12$\n\x0b\x63oncurrency\x18\x07 \x01(\x0b\x32\x0f.v1.Concurrency\x12\x17\n\ncron_input\x18\x08 \x01(\tH\x00\x88\x01\x01\x12\x30\n\x0fon_failure_task\x18\t \x01(\x0b\x32\x12.v1.CreateTaskOptsH\x01\x88\x01\x01\x12\'\n\x06sticky\x18\n \x01(\x0e\x32\x12.v1.StickyStrategyH\x02\x88\x01\x01\x12\x1d\n\x10\x64\x65\x66\x61ult_priority\x18\x0b \x01(\x05H\x03\x88\x01\x01\x12(\n\x0f\x63oncurrency_arr\x18\x0c \x03(\x0b\x32\x0f.v1.Concurrency\x12*\n\x0f\x64\x65\x66\x61ult_filters\x18\r \x03(\x0b\x32\x11.v1.DefaultFilter\x12\x1e\n\x11input_json_schema\x18\x0e \x01(\x0cH\x04\x88\x01\x01\x42\r\n\x0b_cron_inputB\x12\n\x10_on_failure_taskB\t\n\x07_stickyB\x13\n\x11_default_priorityB\x14\n\x12_input_json_schema\"T\n\rDefaultFilter\x12\x12\n\nexpression\x18\x01 \x01(\t\x12\r\n\x05scope\x18\x02 \x01(\t\x12\x14\n\x07payload\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x42\n\n\x08_payload\"\x93\x01\n\x0b\x43oncurrency\x12\x12\n\nexpression\x18\x01 \x01(\t\x12\x15\n\x08max_runs\x18\x02 \x01(\x05H\x00\x88\x01\x01\x12\x39\n\x0elimit_strategy\x18\x03 \x01(\x0e\x32\x1c.v1.ConcurrencyLimitStrategyH\x01\x88\x01\x01\x42\x0b\n\t_max_runsB\x11\n\x0f_limit_strategy\"\xb7\x05\n\x0e\x43reateTaskOpts\x12\x13\n\x0breadable_id\x18\x01 \x01(\t\x12\x0e\n\x06\x61\x63tion\x18\x02 \x01(\t\x12\x0f\n\x07timeout\x18\x03 \x01(\t\x12\x0e\n\x06inputs\x18\x04 \x01(\t\x12\x0f\n\x07parents\x18\x05 \x03(\t\x12\x0f\n\x07retries\x18\x06 \x01(\x05\x12,\n\x0brate_limits\x18\x07 \x03(\x0b\x32\x17.v1.CreateTaskRateLimit\x12;\n\rworker_labels\x18\x08 \x03(\x0b\x32$.v1.CreateTaskOpts.WorkerLabelsEntry\x12\x1b\n\x0e\x62\x61\x63koff_factor\x18\t \x01(\x02H\x00\x88\x01\x01\x12 \n\x13\x62\x61\x63koff_max_seconds\x18\n \x01(\x05H\x01\x88\x01\x01\x12$\n\x0b\x63oncurrency\x18\x0b \x03(\x0b\x32\x0f.v1.Concurrency\x12+\n\nconditions\x18\x0c \x01(\x0b\x32\x12.v1.TaskConditionsH\x02\x88\x01\x01\x12\x1d\n\x10schedule_timeout\x18\r \x01(\tH\x03\x88\x01\x01\x12\x12\n\nis_durable\x18\x0e \x01(\x08\x12;\n\rslot_requests\x18\x0f \x03(\x0b\x32$.v1.CreateTaskOpts.SlotRequestsEntry\x1aL\n\x11WorkerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.v1.DesiredWorkerLabels:\x02\x38\x01\x1a\x33\n\x11SlotRequestsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x42\x11\n\x0f_backoff_factorB\x16\n\x14_backoff_max_secondsB\r\n\x0b_conditionsB\x13\n\x11_schedule_timeout\"\xfd\x01\n\x13\x43reateTaskRateLimit\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x12\n\x05units\x18\x02 \x01(\x05H\x00\x88\x01\x01\x12\x15\n\x08key_expr\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x17\n\nunits_expr\x18\x04 \x01(\tH\x02\x88\x01\x01\x12\x1e\n\x11limit_values_expr\x18\x05 \x01(\tH\x03\x88\x01\x01\x12,\n\x08\x64uration\x18\x06 \x01(\x0e\x32\x15.v1.RateLimitDurationH\x04\x88\x01\x01\x42\x08\n\x06_unitsB\x0b\n\t_key_exprB\r\n\x0b_units_exprB\x14\n\x12_limit_values_exprB\x0b\n\t_duration\"@\n\x1d\x43reateWorkflowVersionResponse\x12\n\n\x02id\x18\x01 \x01(\t\x12\x13\n\x0bworkflow_id\x18\x02 \x01(\t\"+\n\x14GetRunDetailsRequest\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\"\xaa\x01\n\rTaskRunDetail\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\x12\x1d\n\x06status\x18\x02 \x01(\x0e\x32\r.v1.RunStatus\x12\x12\n\x05\x65rror\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06output\x18\x04 \x01(\x0cH\x01\x88\x01\x01\x12\x13\n\x0breadable_id\x18\x05 \x01(\t\x12\x12\n\nis_evicted\x18\x06 \x01(\x08\x42\x08\n\x06_errorB\t\n\x07_output\"\x84\x02\n\x15GetRunDetailsResponse\x12\r\n\x05input\x18\x01 \x01(\x0c\x12\x1d\n\x06status\x18\x02 \x01(\x0e\x32\r.v1.RunStatus\x12:\n\ttask_runs\x18\x03 \x03(\x0b\x32\'.v1.GetRunDetailsResponse.TaskRunsEntry\x12\x0c\n\x04\x64one\x18\x04 \x01(\x08\x12\x1b\n\x13\x61\x64\x64itional_metadata\x18\x05 \x01(\x0c\x12\x12\n\nis_evicted\x18\x06 \x01(\x08\x1a\x42\n\rTaskRunsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12 \n\x05value\x18\x02 \x01(\x0b\x32\x11.v1.TaskRunDetail:\x02\x38\x01*$\n\x0eStickyStrategy\x12\x08\n\x04SOFT\x10\x00\x12\x08\n\x04HARD\x10\x01*]\n\x11RateLimitDuration\x12\n\n\x06SECOND\x10\x00\x12\n\n\x06MINUTE\x10\x01\x12\x08\n\x04HOUR\x10\x02\x12\x07\n\x03\x44\x41Y\x10\x03\x12\x08\n\x04WEEK\x10\x04\x12\t\n\x05MONTH\x10\x05\x12\x08\n\x04YEAR\x10\x06*[\n\tRunStatus\x12\n\n\x06QUEUED\x10\x00\x12\x0b\n\x07RUNNING\x10\x01\x12\r\n\tCOMPLETED\x10\x02\x12\n\n\x06\x46\x41ILED\x10\x03\x12\r\n\tCANCELLED\x10\x04\x12\x0b\n\x07\x45VICTED\x10\x05*\x7f\n\x18\x43oncurrencyLimitStrategy\x12\x16\n\x12\x43\x41NCEL_IN_PROGRESS\x10\x00\x12\x0f\n\x0b\x44ROP_NEWEST\x10\x01\x12\x10\n\x0cQUEUE_NEWEST\x10\x02\x12\x15\n\x11GROUP_ROUND_ROBIN\x10\x03\x12\x11\n\rCANCEL_NEWEST\x10\x04\x32\xcf\x03\n\x0c\x41\x64minService\x12R\n\x0bPutWorkflow\x12 .v1.CreateWorkflowVersionRequest\x1a!.v1.CreateWorkflowVersionResponse\x12>\n\x0b\x43\x61ncelTasks\x12\x16.v1.CancelTasksRequest\x1a\x17.v1.CancelTasksResponse\x12>\n\x0bReplayTasks\x12\x16.v1.ReplayTasksRequest\x1a\x17.v1.ReplayTasksResponse\x12S\n\x12TriggerWorkflowRun\x12\x1d.v1.TriggerWorkflowRunRequest\x1a\x1e.v1.TriggerWorkflowRunResponse\x12\x44\n\rGetRunDetails\x12\x18.v1.GetRunDetailsRequest\x1a\x19.v1.GetRunDetailsResponse\x12P\n\x11\x42ranchDurableTask\x12\x1c.v1.BranchDurableTaskRequest\x1a\x1d.v1.BranchDurableTaskResponseBBZ@github.com/hatchet-dev/hatchet/internal/services/shared/proto/v1b\x06proto3" pool = ::Google::Protobuf::DescriptorPool.generated_pool pool.add_serialized_file(descriptor_data) diff --git a/sdks/ruby/src/lib/hatchet/trigger_options.rb b/sdks/ruby/src/lib/hatchet/trigger_options.rb index 7eab7fcd53..5ab892bbf2 100644 --- a/sdks/ruby/src/lib/hatchet/trigger_options.rb +++ b/sdks/ruby/src/lib/hatchet/trigger_options.rb @@ -33,6 +33,9 @@ class TriggerWorkflowOptions # @return [Hash, nil] Desired worker labels for scheduling attr_reader :desired_worker_labels + # @return [String, nil] Custom display name for the run + attr_reader :display_name + # @param additional_metadata [Hash, nil] Metadata to attach to the run # @param key [String, nil] Deduplication key # @param priority [Integer, nil] Priority level @@ -41,6 +44,7 @@ class TriggerWorkflowOptions # @param child_index [Integer, nil] Child index # @param sticky [Boolean, nil] Enable sticky scheduling # @param desired_worker_labels [Hash, nil] Worker labels for scheduling + # @param display_name [String, nil] Custom display name for the run def initialize( additional_metadata: nil, key: nil, @@ -49,7 +53,8 @@ def initialize( parent_step_run_id: nil, child_index: nil, sticky: nil, - desired_worker_labels: nil + desired_worker_labels: nil, + display_name: nil ) @additional_metadata = additional_metadata @key = key @@ -59,6 +64,7 @@ def initialize( @child_index = child_index @sticky = sticky @desired_worker_labels = desired_worker_labels + @display_name = display_name end # @return [Hash] @@ -72,6 +78,7 @@ def to_h h[:child_index] = @child_index if @child_index h[:sticky] = @sticky unless @sticky.nil? h[:desired_worker_labels] = @desired_worker_labels if @desired_worker_labels + h[:display_name] = @display_name if @display_name h end end diff --git a/sdks/ruby/src/sig/hatchet/trigger_options.rbs b/sdks/ruby/src/sig/hatchet/trigger_options.rbs index 6d618ffadd..cacc3e8baa 100644 --- a/sdks/ruby/src/sig/hatchet/trigger_options.rbs +++ b/sdks/ruby/src/sig/hatchet/trigger_options.rbs @@ -8,6 +8,7 @@ module Hatchet attr_reader child_index: Integer? attr_reader sticky: bool? attr_reader desired_worker_labels: Hash[Symbol, untyped]? + attr_reader display_name: String? def initialize: ( ?additional_metadata: Hash[String, untyped]?, @@ -17,7 +18,8 @@ module Hatchet ?parent_step_run_id: String?, ?child_index: Integer?, ?sticky: bool?, - ?desired_worker_labels: Hash[Symbol, untyped]? + ?desired_worker_labels: Hash[Symbol, untyped]?, + ?display_name: String? ) -> void def to_h: () -> Hash[Symbol, untyped] diff --git a/sdks/ruby/src/spec/hatchet/clients/grpc/admin_spec.rb b/sdks/ruby/src/spec/hatchet/clients/grpc/admin_spec.rb new file mode 100644 index 0000000000..e9956347b0 --- /dev/null +++ b/sdks/ruby/src/spec/hatchet/clients/grpc/admin_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe Hatchet::Clients::Grpc::Admin do + let(:logger) { instance_double(Logger, info: nil, warn: nil, debug: nil) } + let(:config) do + instance_double( + Hatchet::Config, + logger: logger, + auth_metadata: {}, + ) + end + let(:channel) { instance_double("GRPC::Core::Channel") } + let(:v0_stub) { instance_double(WorkflowService::Stub) } + let(:response) { double("TriggerWorkflowResponse", workflow_run_id: "run-1") } + + subject(:admin) { described_class.new(config: config, channel: channel) } + + before do + allow(config).to receive(:apply_namespace) { |name| name } + allow(admin).to receive(:ensure_connected!) + admin.instance_variable_set(:@v0_stub, v0_stub) + allow(v0_stub).to receive(:trigger_workflow).and_return(response) + end + + describe "#trigger_workflow" do + it "maps display_name onto the trigger request" do + admin.trigger_workflow("my-workflow", input: {}, options: { display_name: "Acme Corp" }) + + expect(v0_stub).to have_received(:trigger_workflow) do |request, metadata:| + expect(request.display_name).to eq("Acme Corp") + expect(metadata).to eq({}) + end + end + + it "leaves display_name unset when not provided" do + admin.trigger_workflow("my-workflow", input: {}) + + expect(v0_stub).to have_received(:trigger_workflow) do |request, _metadata| + expect(request.display_name).to eq("") + end + end + end + + describe "#bulk_trigger_workflow" do + let(:bulk_response) { double("BulkTriggerWorkflowResponse", workflow_run_ids: %w[run-1 run-2]) } + + before do + allow(v0_stub).to receive(:bulk_trigger_workflow).and_return(bulk_response) + end + + it "maps a per-item display_name onto each request" do + admin.bulk_trigger_workflow("my-workflow", [ + { input: {}, options: { display_name: "Alpha" } }, + { input: {}, options: { display_name: "Bravo" } }, + ],) + + expect(v0_stub).to have_received(:bulk_trigger_workflow) do |bulk_request, metadata:| + names = bulk_request.workflows.map(&:display_name) + expect(names).to eq(%w[Alpha Bravo]) + expect(metadata).to eq({}) + end + end + end +end diff --git a/sdks/ruby/src/spec/hatchet/trigger_options_spec.rb b/sdks/ruby/src/spec/hatchet/trigger_options_spec.rb new file mode 100644 index 0000000000..c78496b5a4 --- /dev/null +++ b/sdks/ruby/src/spec/hatchet/trigger_options_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe Hatchet::TriggerWorkflowOptions do + describe "#display_name" do + it "exposes the display name and includes it in to_h" do + options = described_class.new(display_name: "Acme Corp") + + expect(options.display_name).to eq("Acme Corp") + expect(options.to_h).to include(display_name: "Acme Corp") + end + + it "omits display_name from to_h when not provided" do + options = described_class.new + + expect(options.display_name).to be_nil + expect(options.to_h).not_to have_key(:display_name) + end + end +end diff --git a/sdks/typescript/CHANGELOG.md b/sdks/typescript/CHANGELOG.md index 55d479d983..20eb6657ad 100644 --- a/sdks/typescript/CHANGELOG.md +++ b/sdks/typescript/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to Hatchet's TypeScript SDK will be documented in this chang The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Added + +- Added a `displayName` run option to set a custom, human-readable name on a run at trigger time. It is accepted in the options for `run`, `runNoWait`, `runMany`/`runManyNoWait` (per-item), and child spawns (`runChild`/`runChildren`). Single-task runs carry the name on the task; multi-step DAG runs carry it on the DAG (the DAG's step tasks keep their generated names). Empty or whitespace-only values fall back to the generated `-` name, and names longer than 255 characters are stored truncated rather than rejected ([#4259](https://github.com/hatchet-dev/hatchet/issues/4259)). + ## [1.24.3] - 2026-06-17 ### Removed diff --git a/sdks/typescript/src/protoc/google/protobuf/timestamp.ts b/sdks/typescript/src/protoc/google/protobuf/timestamp.ts index ee4b6339ba..4c5e1acda0 100644 --- a/sdks/typescript/src/protoc/google/protobuf/timestamp.ts +++ b/sdks/typescript/src/protoc/google/protobuf/timestamp.ts @@ -1,13 +1,13 @@ // Code generated by protoc-gen-ts_proto. DO NOT EDIT. // versions: // protoc-gen-ts_proto v2.11.8 -// protoc v3.19.1 +// protoc v7.35.1 // source: google/protobuf/timestamp.proto /* eslint-disable */ -import { BinaryReader, BinaryWriter } from '@bufbuild/protobuf/wire'; +import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire"; -export const protobufPackage = 'google.protobuf'; +export const protobufPackage = "google.protobuf"; /** * A Timestamp represents a point in time independent of any time zone or local @@ -82,8 +82,8 @@ export const protobufPackage = 'google.protobuf'; * {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional * seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), * are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone - * is required. A proto3 JSON serializer should always use UTC (as indicated by - * "Z") when printing the Timestamp type and a proto3 JSON parser should be + * is required. A ProtoJSON serializer should always use UTC (as indicated by + * "Z") when printing the Timestamp type and a ProtoJSON parser should be * able to accept both UTC and other timezones (as indicated by an offset). * * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past @@ -97,20 +97,21 @@ export const protobufPackage = 'google.protobuf'; * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with * the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use * the Joda Time's [`ISODateTimeFormat.dateTime()`]( - * http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D + * http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime() * ) to obtain a formatter capable of generating timestamps in this format. */ export interface Timestamp { /** - * Represents seconds of UTC time since Unix epoch - * 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to - * 9999-12-31T23:59:59Z inclusive. + * Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must + * be between -62135596800 and 253402300799 inclusive (which corresponds to + * 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z). */ seconds: number; /** - * Non-negative fractions of a second at nanosecond resolution. Negative - * second values with fractions must still have non-negative nanos values - * that count forward in time. Must be from 0 to 999,999,999 + * Non-negative fractions of a second at nanosecond resolution. This field is + * the nanosecond portion of the duration, not an alternative to seconds. + * Negative second values with fractions must still have non-negative nanos + * values that count forward in time. Must be between 0 and 999,999,999 * inclusive. */ nanos: number; @@ -194,23 +195,19 @@ export const Timestamp: MessageFns = { type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined; -export type DeepPartial = T extends Builtin - ? T - : T extends globalThis.Array - ? globalThis.Array> - : T extends ReadonlyArray - ? ReadonlyArray> - : T extends {} - ? { [K in keyof T]?: DeepPartial } - : Partial; +export type DeepPartial = T extends Builtin ? T + : T extends globalThis.Array ? globalThis.Array> + : T extends ReadonlyArray ? ReadonlyArray> + : T extends {} ? { [K in keyof T]?: DeepPartial } + : Partial; function longToNumber(int64: { toString(): string }): number { const num = globalThis.Number(int64.toString()); if (num > globalThis.Number.MAX_SAFE_INTEGER) { - throw new globalThis.Error('Value is larger than Number.MAX_SAFE_INTEGER'); + throw new globalThis.Error("Value is larger than Number.MAX_SAFE_INTEGER"); } if (num < globalThis.Number.MIN_SAFE_INTEGER) { - throw new globalThis.Error('Value is smaller than Number.MIN_SAFE_INTEGER'); + throw new globalThis.Error("Value is smaller than Number.MIN_SAFE_INTEGER"); } return num; } diff --git a/sdks/typescript/src/protoc/v1/shared/condition.ts b/sdks/typescript/src/protoc/v1/shared/condition.ts index ae8ce105c0..7e1bdb74a0 100644 --- a/sdks/typescript/src/protoc/v1/shared/condition.ts +++ b/sdks/typescript/src/protoc/v1/shared/condition.ts @@ -1,14 +1,14 @@ // Code generated by protoc-gen-ts_proto. DO NOT EDIT. // versions: // protoc-gen-ts_proto v2.11.8 -// protoc v3.19.1 +// protoc v7.35.1 // source: v1/shared/condition.proto /* eslint-disable */ -import { BinaryReader, BinaryWriter } from '@bufbuild/protobuf/wire'; -import { Timestamp } from '../../google/protobuf/timestamp'; +import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire"; +import { Timestamp } from "../../google/protobuf/timestamp"; -export const protobufPackage = 'v1'; +export const protobufPackage = "v1"; export enum Action { CREATE = 0, @@ -21,19 +21,19 @@ export enum Action { export function actionFromJSON(object: any): Action { switch (object) { case 0: - case 'CREATE': + case "CREATE": return Action.CREATE; case 1: - case 'QUEUE': + case "QUEUE": return Action.QUEUE; case 2: - case 'CANCEL': + case "CANCEL": return Action.CANCEL; case 3: - case 'SKIP': + case "SKIP": return Action.SKIP; case -1: - case 'UNRECOGNIZED': + case "UNRECOGNIZED": default: return Action.UNRECOGNIZED; } @@ -42,16 +42,16 @@ export function actionFromJSON(object: any): Action { export function actionToJSON(object: Action): string { switch (object) { case Action.CREATE: - return 'CREATE'; + return "CREATE"; case Action.QUEUE: - return 'QUEUE'; + return "QUEUE"; case Action.CANCEL: - return 'CANCEL'; + return "CANCEL"; case Action.SKIP: - return 'SKIP'; + return "SKIP"; case Action.UNRECOGNIZED: default: - return 'UNRECOGNIZED'; + return "UNRECOGNIZED"; } } @@ -69,7 +69,9 @@ export interface ParentOverrideMatchCondition { } export interface SleepMatchCondition { - base: BaseMatchCondition | undefined; + base: + | BaseMatchCondition + | undefined; /** a duration string indicating how long to sleep */ sleepFor: string; } @@ -94,21 +96,21 @@ export interface DurableEventListenerConditions { } function createBaseBaseMatchCondition(): BaseMatchCondition { - return { readableDataKey: '', action: 0, orGroupId: '', expression: '' }; + return { readableDataKey: "", action: 0, orGroupId: "", expression: "" }; } export const BaseMatchCondition: MessageFns = { encode(message: BaseMatchCondition, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { - if (message.readableDataKey !== '') { + if (message.readableDataKey !== "") { writer.uint32(10).string(message.readableDataKey); } if (message.action !== 0) { writer.uint32(16).int32(message.action); } - if (message.orGroupId !== '') { + if (message.orGroupId !== "") { writer.uint32(26).string(message.orGroupId); } - if (message.expression !== '') { + if (message.expression !== "") { writer.uint32(34).string(message.expression); } return writer; @@ -167,30 +169,30 @@ export const BaseMatchCondition: MessageFns = { readableDataKey: isSet(object.readableDataKey) ? globalThis.String(object.readableDataKey) : isSet(object.readable_data_key) - ? globalThis.String(object.readable_data_key) - : '', + ? globalThis.String(object.readable_data_key) + : "", action: isSet(object.action) ? actionFromJSON(object.action) : 0, orGroupId: isSet(object.orGroupId) ? globalThis.String(object.orGroupId) : isSet(object.or_group_id) - ? globalThis.String(object.or_group_id) - : '', - expression: isSet(object.expression) ? globalThis.String(object.expression) : '', + ? globalThis.String(object.or_group_id) + : "", + expression: isSet(object.expression) ? globalThis.String(object.expression) : "", }; }, toJSON(message: BaseMatchCondition): unknown { const obj: any = {}; - if (message.readableDataKey !== '') { + if (message.readableDataKey !== "") { obj.readableDataKey = message.readableDataKey; } if (message.action !== 0) { obj.action = actionToJSON(message.action); } - if (message.orGroupId !== '') { + if (message.orGroupId !== "") { obj.orGroupId = message.orGroupId; } - if (message.expression !== '') { + if (message.expression !== "") { obj.expression = message.expression; } return obj; @@ -201,27 +203,24 @@ export const BaseMatchCondition: MessageFns = { }, fromPartial(object: DeepPartial): BaseMatchCondition { const message = createBaseBaseMatchCondition(); - message.readableDataKey = object.readableDataKey ?? ''; + message.readableDataKey = object.readableDataKey ?? ""; message.action = object.action ?? 0; - message.orGroupId = object.orGroupId ?? ''; - message.expression = object.expression ?? ''; + message.orGroupId = object.orGroupId ?? ""; + message.expression = object.expression ?? ""; return message; }, }; function createBaseParentOverrideMatchCondition(): ParentOverrideMatchCondition { - return { base: undefined, parentReadableId: '' }; + return { base: undefined, parentReadableId: "" }; } export const ParentOverrideMatchCondition: MessageFns = { - encode( - message: ParentOverrideMatchCondition, - writer: BinaryWriter = new BinaryWriter() - ): BinaryWriter { + encode(message: ParentOverrideMatchCondition, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { if (message.base !== undefined) { BaseMatchCondition.encode(message.base, writer.uint32(10).fork()).join(); } - if (message.parentReadableId !== '') { + if (message.parentReadableId !== "") { writer.uint32(18).string(message.parentReadableId); } return writer; @@ -265,8 +264,8 @@ export const ParentOverrideMatchCondition: MessageFns): ParentOverrideMatchCondition { const message = createBaseParentOverrideMatchCondition(); - message.base = - object.base !== undefined && object.base !== null - ? BaseMatchCondition.fromPartial(object.base) - : undefined; - message.parentReadableId = object.parentReadableId ?? ''; + message.base = (object.base !== undefined && object.base !== null) + ? BaseMatchCondition.fromPartial(object.base) + : undefined; + message.parentReadableId = object.parentReadableId ?? ""; return message; }, }; function createBaseSleepMatchCondition(): SleepMatchCondition { - return { base: undefined, sleepFor: '' }; + return { base: undefined, sleepFor: "" }; } export const SleepMatchCondition: MessageFns = { @@ -304,7 +302,7 @@ export const SleepMatchCondition: MessageFns = { if (message.base !== undefined) { BaseMatchCondition.encode(message.base, writer.uint32(10).fork()).join(); } - if (message.sleepFor !== '') { + if (message.sleepFor !== "") { writer.uint32(18).string(message.sleepFor); } return writer; @@ -348,8 +346,8 @@ export const SleepMatchCondition: MessageFns = { sleepFor: isSet(object.sleepFor) ? globalThis.String(object.sleepFor) : isSet(object.sleep_for) - ? globalThis.String(object.sleep_for) - : '', + ? globalThis.String(object.sleep_for) + : "", }; }, @@ -358,7 +356,7 @@ export const SleepMatchCondition: MessageFns = { if (message.base !== undefined) { obj.base = BaseMatchCondition.toJSON(message.base); } - if (message.sleepFor !== '') { + if (message.sleepFor !== "") { obj.sleepFor = message.sleepFor; } return obj; @@ -369,33 +367,24 @@ export const SleepMatchCondition: MessageFns = { }, fromPartial(object: DeepPartial): SleepMatchCondition { const message = createBaseSleepMatchCondition(); - message.base = - object.base !== undefined && object.base !== null - ? BaseMatchCondition.fromPartial(object.base) - : undefined; - message.sleepFor = object.sleepFor ?? ''; + message.base = (object.base !== undefined && object.base !== null) + ? BaseMatchCondition.fromPartial(object.base) + : undefined; + message.sleepFor = object.sleepFor ?? ""; return message; }, }; function createBaseUserEventMatchCondition(): UserEventMatchCondition { - return { - base: undefined, - userEventKey: '', - eventScope: undefined, - considerEventsSince: undefined, - }; + return { base: undefined, userEventKey: "", eventScope: undefined, considerEventsSince: undefined }; } export const UserEventMatchCondition: MessageFns = { - encode( - message: UserEventMatchCondition, - writer: BinaryWriter = new BinaryWriter() - ): BinaryWriter { + encode(message: UserEventMatchCondition, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { if (message.base !== undefined) { BaseMatchCondition.encode(message.base, writer.uint32(10).fork()).join(); } - if (message.userEventKey !== '') { + if (message.userEventKey !== "") { writer.uint32(18).string(message.userEventKey); } if (message.eventScope !== undefined) { @@ -461,18 +450,18 @@ export const UserEventMatchCondition: MessageFns = { userEventKey: isSet(object.userEventKey) ? globalThis.String(object.userEventKey) : isSet(object.user_event_key) - ? globalThis.String(object.user_event_key) - : '', + ? globalThis.String(object.user_event_key) + : "", eventScope: isSet(object.eventScope) ? globalThis.String(object.eventScope) : isSet(object.event_scope) - ? globalThis.String(object.event_scope) - : undefined, + ? globalThis.String(object.event_scope) + : undefined, considerEventsSince: isSet(object.considerEventsSince) ? fromJsonTimestamp(object.considerEventsSince) : isSet(object.consider_events_since) - ? fromJsonTimestamp(object.consider_events_since) - : undefined, + ? fromJsonTimestamp(object.consider_events_since) + : undefined, }; }, @@ -481,7 +470,7 @@ export const UserEventMatchCondition: MessageFns = { if (message.base !== undefined) { obj.base = BaseMatchCondition.toJSON(message.base); } - if (message.userEventKey !== '') { + if (message.userEventKey !== "") { obj.userEventKey = message.userEventKey; } if (message.eventScope !== undefined) { @@ -498,11 +487,10 @@ export const UserEventMatchCondition: MessageFns = { }, fromPartial(object: DeepPartial): UserEventMatchCondition { const message = createBaseUserEventMatchCondition(); - message.base = - object.base !== undefined && object.base !== null - ? BaseMatchCondition.fromPartial(object.base) - : undefined; - message.userEventKey = object.userEventKey ?? ''; + message.base = (object.base !== undefined && object.base !== null) + ? BaseMatchCondition.fromPartial(object.base) + : undefined; + message.userEventKey = object.userEventKey ?? ""; message.eventScope = object.eventScope ?? undefined; message.considerEventsSince = object.considerEventsSince ?? undefined; return message; @@ -539,9 +527,7 @@ export const TaskConditions: MessageFns = { break; } - message.parentOverrideConditions.push( - ParentOverrideMatchCondition.decode(reader, reader.uint32()) - ); + message.parentOverrideConditions.push(ParentOverrideMatchCondition.decode(reader, reader.uint32())); continue; } case 2: { @@ -574,20 +560,18 @@ export const TaskConditions: MessageFns = { parentOverrideConditions: globalThis.Array.isArray(object?.parentOverrideConditions) ? object.parentOverrideConditions.map((e: any) => ParentOverrideMatchCondition.fromJSON(e)) : globalThis.Array.isArray(object?.parent_override_conditions) - ? object.parent_override_conditions.map((e: any) => - ParentOverrideMatchCondition.fromJSON(e) - ) - : [], + ? object.parent_override_conditions.map((e: any) => ParentOverrideMatchCondition.fromJSON(e)) + : [], sleepConditions: globalThis.Array.isArray(object?.sleepConditions) ? object.sleepConditions.map((e: any) => SleepMatchCondition.fromJSON(e)) : globalThis.Array.isArray(object?.sleep_conditions) - ? object.sleep_conditions.map((e: any) => SleepMatchCondition.fromJSON(e)) - : [], + ? object.sleep_conditions.map((e: any) => SleepMatchCondition.fromJSON(e)) + : [], userEventConditions: globalThis.Array.isArray(object?.userEventConditions) ? object.userEventConditions.map((e: any) => UserEventMatchCondition.fromJSON(e)) : globalThis.Array.isArray(object?.user_event_conditions) - ? object.user_event_conditions.map((e: any) => UserEventMatchCondition.fromJSON(e)) - : [], + ? object.user_event_conditions.map((e: any) => UserEventMatchCondition.fromJSON(e)) + : [], }; }, @@ -602,9 +586,7 @@ export const TaskConditions: MessageFns = { obj.sleepConditions = message.sleepConditions.map((e) => SleepMatchCondition.toJSON(e)); } if (message.userEventConditions?.length) { - obj.userEventConditions = message.userEventConditions.map((e) => - UserEventMatchCondition.toJSON(e) - ); + obj.userEventConditions = message.userEventConditions.map((e) => UserEventMatchCondition.toJSON(e)); } return obj; }, @@ -615,12 +597,9 @@ export const TaskConditions: MessageFns = { fromPartial(object: DeepPartial): TaskConditions { const message = createBaseTaskConditions(); message.parentOverrideConditions = - object.parentOverrideConditions?.map((e) => ParentOverrideMatchCondition.fromPartial(e)) || - []; - message.sleepConditions = - object.sleepConditions?.map((e) => SleepMatchCondition.fromPartial(e)) || []; - message.userEventConditions = - object.userEventConditions?.map((e) => UserEventMatchCondition.fromPartial(e)) || []; + object.parentOverrideConditions?.map((e) => ParentOverrideMatchCondition.fromPartial(e)) || []; + message.sleepConditions = object.sleepConditions?.map((e) => SleepMatchCondition.fromPartial(e)) || []; + message.userEventConditions = object.userEventConditions?.map((e) => UserEventMatchCondition.fromPartial(e)) || []; return message; }, }; @@ -630,10 +609,7 @@ function createBaseDurableEventListenerConditions(): DurableEventListenerConditi } export const DurableEventListenerConditions: MessageFns = { - encode( - message: DurableEventListenerConditions, - writer: BinaryWriter = new BinaryWriter() - ): BinaryWriter { + encode(message: DurableEventListenerConditions, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { for (const v of message.sleepConditions) { SleepMatchCondition.encode(v!, writer.uint32(10).fork()).join(); } @@ -680,13 +656,13 @@ export const DurableEventListenerConditions: MessageFns SleepMatchCondition.fromJSON(e)) : globalThis.Array.isArray(object?.sleep_conditions) - ? object.sleep_conditions.map((e: any) => SleepMatchCondition.fromJSON(e)) - : [], + ? object.sleep_conditions.map((e: any) => SleepMatchCondition.fromJSON(e)) + : [], userEventConditions: globalThis.Array.isArray(object?.userEventConditions) ? object.userEventConditions.map((e: any) => UserEventMatchCondition.fromJSON(e)) : globalThis.Array.isArray(object?.user_event_conditions) - ? object.user_event_conditions.map((e: any) => UserEventMatchCondition.fromJSON(e)) - : [], + ? object.user_event_conditions.map((e: any) => UserEventMatchCondition.fromJSON(e)) + : [], }; }, @@ -696,9 +672,7 @@ export const DurableEventListenerConditions: MessageFns SleepMatchCondition.toJSON(e)); } if (message.userEventConditions?.length) { - obj.userEventConditions = message.userEventConditions.map((e) => - UserEventMatchCondition.toJSON(e) - ); + obj.userEventConditions = message.userEventConditions.map((e) => UserEventMatchCondition.toJSON(e)); } return obj; }, @@ -708,25 +682,19 @@ export const DurableEventListenerConditions: MessageFns): DurableEventListenerConditions { const message = createBaseDurableEventListenerConditions(); - message.sleepConditions = - object.sleepConditions?.map((e) => SleepMatchCondition.fromPartial(e)) || []; - message.userEventConditions = - object.userEventConditions?.map((e) => UserEventMatchCondition.fromPartial(e)) || []; + message.sleepConditions = object.sleepConditions?.map((e) => SleepMatchCondition.fromPartial(e)) || []; + message.userEventConditions = object.userEventConditions?.map((e) => UserEventMatchCondition.fromPartial(e)) || []; return message; }, }; type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined; -export type DeepPartial = T extends Builtin - ? T - : T extends globalThis.Array - ? globalThis.Array> - : T extends ReadonlyArray - ? ReadonlyArray> - : T extends {} - ? { [K in keyof T]?: DeepPartial } - : Partial; +export type DeepPartial = T extends Builtin ? T + : T extends globalThis.Array ? globalThis.Array> + : T extends ReadonlyArray ? ReadonlyArray> + : T extends {} ? { [K in keyof T]?: DeepPartial } + : Partial; function toTimestamp(date: Date): Timestamp { const seconds = Math.trunc(date.getTime() / 1_000); @@ -743,7 +711,7 @@ function fromTimestamp(t: Timestamp): Date { function fromJsonTimestamp(o: any): Date { if (o instanceof globalThis.Date) { return o; - } else if (typeof o === 'string') { + } else if (typeof o === "string") { return new globalThis.Date(o); } else { return fromTimestamp(Timestamp.fromJSON(o)); diff --git a/sdks/typescript/src/protoc/v1/shared/trigger.ts b/sdks/typescript/src/protoc/v1/shared/trigger.ts index 6b3a49268d..fc663db04d 100644 --- a/sdks/typescript/src/protoc/v1/shared/trigger.ts +++ b/sdks/typescript/src/protoc/v1/shared/trigger.ts @@ -1,7 +1,7 @@ // Code generated by protoc-gen-ts_proto. DO NOT EDIT. // versions: // protoc-gen-ts_proto v2.11.8 -// protoc v3.19.1 +// protoc v7.35.1 // source: v1/shared/trigger.proto /* eslint-disable */ @@ -120,6 +120,8 @@ export interface TriggerWorkflowRequest { priority?: number | undefined; /** (optional) the desired worker labels for the workflow run, which will be used to determine which workers can pick up the workflow's tasks. if not set, defaults to an empty set of labels, which means any worker can pick up the tasks. */ desiredWorkerLabels: { [key: string]: DesiredWorkerLabels }; + /** (optional) a custom display name for the run; falls back to "-" if unset */ + displayName?: string | undefined; } export interface TriggerWorkflowRequest_DesiredWorkerLabelsEntry { @@ -279,6 +281,7 @@ function createBaseTriggerWorkflowRequest(): TriggerWorkflowRequest { desiredWorkerId: undefined, priority: undefined, desiredWorkerLabels: {}, + displayName: undefined, }; } @@ -319,6 +322,9 @@ export const TriggerWorkflowRequest: MessageFns = { ).join(); } ); + if (message.displayName !== undefined) { + writer.uint32(90).string(message.displayName); + } return writer; }, @@ -415,6 +421,14 @@ export const TriggerWorkflowRequest: MessageFns = { } continue; } + case 11: { + if (tag !== 90) { + break; + } + + message.displayName = reader.string(); + continue; + } } if ((tag & 7) === 4 || tag === 0) { break; @@ -476,6 +490,11 @@ export const TriggerWorkflowRequest: MessageFns = { {} ) : {}, + displayName: isSet(object.displayName) + ? globalThis.String(object.displayName) + : isSet(object.display_name) + ? globalThis.String(object.display_name) + : undefined, }; }, @@ -520,6 +539,9 @@ export const TriggerWorkflowRequest: MessageFns = { }); } } + if (message.displayName !== undefined) { + obj.displayName = message.displayName; + } return obj; }, @@ -551,6 +573,7 @@ export const TriggerWorkflowRequest: MessageFns = { }, {} ); + message.displayName = object.displayName ?? undefined; return message; }, }; diff --git a/sdks/typescript/src/protoc/v1/workflows.ts b/sdks/typescript/src/protoc/v1/workflows.ts index 6e729c1514..e0a3aa13bd 100644 --- a/sdks/typescript/src/protoc/v1/workflows.ts +++ b/sdks/typescript/src/protoc/v1/workflows.ts @@ -1,7 +1,7 @@ // Code generated by protoc-gen-ts_proto. DO NOT EDIT. // versions: // protoc-gen-ts_proto v2.11.8 -// protoc v3.19.1 +// protoc v7.35.1 // source: v1/workflows.proto /* eslint-disable */ @@ -253,6 +253,8 @@ export interface TriggerWorkflowRunRequest { additionalMetadata: Uint8Array; priority?: number | undefined; desiredWorkerLabels: { [key: string]: DesiredWorkerLabels }; + /** (optional) a custom display name for the run; falls back to a generated name if unset */ + displayName?: string | undefined; } export interface TriggerWorkflowRunRequest_DesiredWorkerLabelsEntry { @@ -878,6 +880,7 @@ function createBaseTriggerWorkflowRunRequest(): TriggerWorkflowRunRequest { additionalMetadata: new Uint8Array(0), priority: undefined, desiredWorkerLabels: {}, + displayName: undefined, }; } @@ -906,6 +909,9 @@ export const TriggerWorkflowRunRequest: MessageFns = ).join(); } ); + if (message.displayName !== undefined) { + writer.uint32(50).string(message.displayName); + } return writer; }, @@ -962,6 +968,14 @@ export const TriggerWorkflowRunRequest: MessageFns = } continue; } + case 6: { + if (tag !== 50) { + break; + } + + message.displayName = reader.string(); + continue; + } } if ((tag & 7) === 4 || tag === 0) { break; @@ -1002,6 +1016,11 @@ export const TriggerWorkflowRunRequest: MessageFns = {} ) : {}, + displayName: isSet(object.displayName) + ? globalThis.String(object.displayName) + : isSet(object.display_name) + ? globalThis.String(object.display_name) + : undefined, }; }, @@ -1031,6 +1050,9 @@ export const TriggerWorkflowRunRequest: MessageFns = }); } } + if (message.displayName !== undefined) { + obj.displayName = message.displayName; + } return obj; }, @@ -1057,6 +1079,7 @@ export const TriggerWorkflowRunRequest: MessageFns = }, {} ); + message.displayName = object.displayName ?? undefined; return message; }, }; diff --git a/sdks/typescript/src/v1/client/admin.test.ts b/sdks/typescript/src/v1/client/admin.test.ts index c3439c38f1..63d4c94121 100644 --- a/sdks/typescript/src/v1/client/admin.test.ts +++ b/sdks/typescript/src/v1/client/admin.test.ts @@ -73,3 +73,39 @@ describe('AdminClient workflow name normalization', () => { ); }); }); + +describe('AdminClient display name', () => { + it('runWorkflow maps displayName onto the trigger request', async () => { + const admin = createMockAdmin(); + await admin.runWorkflow('my-workflow', {}, { displayName: 'Acme Corp' }); + + expect(admin.workflowsGrpc.triggerWorkflow).toHaveBeenCalledWith( + expect.objectContaining({ displayName: 'Acme Corp' }) + ); + }); + + it('runWorkflow leaves displayName undefined when not provided', async () => { + const admin = createMockAdmin(); + await admin.runWorkflow('my-workflow', {}); + + const request = (admin.workflowsGrpc.triggerWorkflow as jest.Mock).mock.calls[0][0]; + expect(request.displayName).toBeUndefined(); + }); + + it('runWorkflows maps a per-item displayName in batch', async () => { + const admin = createMockAdmin(); + await admin.runWorkflows([ + { workflowName: 'WorkflowOne', input: {}, options: { displayName: 'Alpha' } }, + { workflowName: 'WorkflowTwo', input: {}, options: { displayName: 'Bravo' } }, + ]); + + expect(admin.workflowsGrpc.bulkTriggerWorkflow).toHaveBeenCalledWith( + expect.objectContaining({ + workflows: expect.arrayContaining([ + expect.objectContaining({ displayName: 'Alpha' }), + expect.objectContaining({ displayName: 'Bravo' }), + ]), + }) + ); + }); +}); diff --git a/sdks/typescript/src/v1/client/admin.ts b/sdks/typescript/src/v1/client/admin.ts index 87540053cc..4a9f2b4e6e 100644 --- a/sdks/typescript/src/v1/client/admin.ts +++ b/sdks/typescript/src/v1/client/admin.ts @@ -132,6 +132,7 @@ export class AdminClient { desiredWorkerId?: string | undefined; priority?: Priority; desiredWorkerLabels?: Record; + displayName?: string | undefined; _standaloneTaskName?: string | undefined; } ) { @@ -216,6 +217,7 @@ export class AdminClient { desiredWorkerId?: string | undefined; priority?: Priority; desiredWorkerLabels?: Record; + displayName?: string | undefined; _standaloneTaskName?: string | undefined; }; }>, diff --git a/sdks/typescript/src/v1/client/worker/context.ts b/sdks/typescript/src/v1/client/worker/context.ts index 87ae750b86..5d6057d7d6 100644 --- a/sdks/typescript/src/v1/client/worker/context.ts +++ b/sdks/typescript/src/v1/client/worker/context.ts @@ -1161,6 +1161,7 @@ export class DurableContext extends Context { desiredWorkerId: options?.sticky ? this.worker.id() : undefined, priority: options?.priority, desiredWorkerLabels: {}, + displayName: options?.displayName, }; return { workflowName, triggerOpts }; diff --git a/sdks/typescript/src/v1/declaration.ts b/sdks/typescript/src/v1/declaration.ts index 49ad94baae..74f6c8d8ee 100644 --- a/sdks/typescript/src/v1/declaration.ts +++ b/sdks/typescript/src/v1/declaration.ts @@ -75,6 +75,13 @@ export type RunOpts = { */ priority?: Priority; + /** + * (optional) a custom display name for the run, shown in the dashboard. + * The engine trims and truncates it; an empty/whitespace value falls back to + * the generated `-` label. + */ + displayName?: string; + /** * (optional) if the task run should be run on the same worker. * only used if spawned from within a parent task. From dcfe4b71839509c71a122f54b92981a240083145 Mon Sep 17 00:00:00 2001 From: Hugo martins Date: Wed, 8 Jul 2026 03:57:01 +0200 Subject: [PATCH 2/4] fix(ts): use array destructuring in admin display name test (eslint) Co-Authored-By: Claude Opus 4.8 (1M context) --- sdks/typescript/src/v1/client/admin.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdks/typescript/src/v1/client/admin.test.ts b/sdks/typescript/src/v1/client/admin.test.ts index 63d4c94121..cf2183eae5 100644 --- a/sdks/typescript/src/v1/client/admin.test.ts +++ b/sdks/typescript/src/v1/client/admin.test.ts @@ -88,7 +88,7 @@ describe('AdminClient display name', () => { const admin = createMockAdmin(); await admin.runWorkflow('my-workflow', {}); - const request = (admin.workflowsGrpc.triggerWorkflow as jest.Mock).mock.calls[0][0]; + const [[request]] = (admin.workflowsGrpc.triggerWorkflow as jest.Mock).mock.calls; expect(request.displayName).toBeUndefined(); }); From 6253630ef6c3383a7b62c908638a92ddd50a2703 Mon Sep 17 00:00:00 2001 From: Hugo martins Date: Wed, 8 Jul 2026 04:02:06 +0200 Subject: [PATCH 3/4] fix: satisfy CI lint (prettier on regenerated protoc, pydoclint display_name) - Run prettier over condition.ts / timestamp.ts, which were regenerated with protoc v7.35.1 (double quotes) but missed the prettier:fix pass, unlike the other v7.35.1-regenerated protoc files. Fixes prettier:check. - Document the new `display_name` param in the 9 run/run_no_wait/create_bulk_run_item docstrings. Fixes pydoclint DOC101/DOC103. Co-Authored-By: Claude Opus 4.8 (1M context) --- sdks/python/hatchet_sdk/runnables/workflow.py | 9 + .../src/protoc/google/protobuf/timestamp.ts | 22 +- .../src/protoc/v1/shared/condition.ts | 210 ++++++++++-------- 3 files changed, 143 insertions(+), 98 deletions(-) diff --git a/sdks/python/hatchet_sdk/runnables/workflow.py b/sdks/python/hatchet_sdk/runnables/workflow.py index 788e343e06..3614db5f9e 100644 --- a/sdks/python/hatchet_sdk/runnables/workflow.py +++ b/sdks/python/hatchet_sdk/runnables/workflow.py @@ -397,6 +397,7 @@ def create_bulk_run_item( :param desired_worker_id: The ID of the desired worker to run the workflow on. :param sticky: Whether to use sticky scheduling for the workflow run. :param desired_worker_labels: A list of desired worker labels for worker affinity. + :param display_name: A custom display name for the workflow run. If not provided, a name is generated automatically. :returns: A `WorkflowRunTriggerConfig` object that can be used to trigger the workflow run, which you then pass into the `run_many` methods. """ @@ -884,6 +885,7 @@ def run_no_wait( :param sticky: Whether to use sticky scheduling for the workflow run. :param desired_worker_id: The ID of the desired worker to run the workflow on. :param desired_worker_labels: A list of desired worker labels for worker affinity. + :param display_name: A custom display name for the workflow run. If not provided, a name is generated automatically. :returns: A `WorkflowRunRef` object representing the reference to the workflow run. @@ -966,6 +968,7 @@ def run( :param sticky: Whether to use sticky scheduling for the workflow run. :param desired_worker_id: The ID of the desired worker to run the workflow on. :param desired_worker_labels: A list of desired worker labels for worker affinity. + :param display_name: A custom display name for the workflow run. If not provided, a name is generated automatically. :returns: The result of the workflow execution as a dictionary, or a WorkflowRunRef if wait_for_result is False. """ @@ -1014,6 +1017,7 @@ async def aio_run_no_wait( :param sticky: Whether to use sticky scheduling for the workflow run. :param desired_worker_id: The ID of the desired worker to run the workflow on. :param desired_worker_labels: A list of desired worker labels for worker affinity. + :param display_name: A custom display name for the workflow run. If not provided, a name is generated automatically. :returns: A `WorkflowRunRef` object representing the reference to the workflow run. @@ -1096,6 +1100,7 @@ async def aio_run( :param sticky: Whether to use sticky scheduling for the workflow run. :param desired_worker_id: The ID of the desired worker to run the workflow on. :param desired_worker_labels: A list of desired worker labels for worker affinity. + :param display_name: A custom display name for the workflow run. If not provided, a name is generated automatically. :returns: The result of the workflow execution as a dictionary, or a WorkflowRunRef if wait_for_result is False. @@ -1884,6 +1889,7 @@ def run( :param sticky: Whether to use sticky scheduling for the workflow run. :param desired_worker_id: The ID of the desired worker to run the workflow on. :param desired_worker_labels: A list of desired worker labels for worker affinity. + :param display_name: A custom display name for the workflow run. If not provided, a name is generated automatically. :returns: The extracted result of the workflow execution, or a TaskRunRef if wait_for_result is False. """ @@ -1975,6 +1981,7 @@ async def aio_run( :param sticky: Whether to use sticky scheduling for the workflow run. :param desired_worker_id: The ID of the desired worker to run the workflow on. :param desired_worker_labels: A list of desired worker labels for worker affinity. + :param display_name: A custom display name for the workflow run. If not provided, a name is generated automatically. :returns: The extracted result of the workflow execution, or a TaskRunRef if wait_for_result is False. """ @@ -2034,6 +2041,7 @@ def run_no_wait( :param sticky: Whether to use sticky scheduling for the workflow run. :param desired_worker_id: The ID of the desired worker to run the workflow on. :param desired_worker_labels: A list of desired worker labels for worker affinity. + :param display_name: A custom display name for the workflow run. If not provided, a name is generated automatically. :returns: A `TaskRunRef` object representing the reference to the workflow run. @@ -2082,6 +2090,7 @@ async def aio_run_no_wait( :param sticky: Whether to use sticky scheduling for the workflow run. :param desired_worker_id: The ID of the desired worker to run the workflow on. :param desired_worker_labels: A list of desired worker labels for worker affinity. + :param display_name: A custom display name for the workflow run. If not provided, a name is generated automatically. :returns: A `TaskRunRef` object representing the reference to the workflow run. diff --git a/sdks/typescript/src/protoc/google/protobuf/timestamp.ts b/sdks/typescript/src/protoc/google/protobuf/timestamp.ts index 4c5e1acda0..f6df430a4d 100644 --- a/sdks/typescript/src/protoc/google/protobuf/timestamp.ts +++ b/sdks/typescript/src/protoc/google/protobuf/timestamp.ts @@ -5,9 +5,9 @@ // source: google/protobuf/timestamp.proto /* eslint-disable */ -import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire"; +import { BinaryReader, BinaryWriter } from '@bufbuild/protobuf/wire'; -export const protobufPackage = "google.protobuf"; +export const protobufPackage = 'google.protobuf'; /** * A Timestamp represents a point in time independent of any time zone or local @@ -195,19 +195,23 @@ export const Timestamp: MessageFns = { type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined; -export type DeepPartial = T extends Builtin ? T - : T extends globalThis.Array ? globalThis.Array> - : T extends ReadonlyArray ? ReadonlyArray> - : T extends {} ? { [K in keyof T]?: DeepPartial } - : Partial; +export type DeepPartial = T extends Builtin + ? T + : T extends globalThis.Array + ? globalThis.Array> + : T extends ReadonlyArray + ? ReadonlyArray> + : T extends {} + ? { [K in keyof T]?: DeepPartial } + : Partial; function longToNumber(int64: { toString(): string }): number { const num = globalThis.Number(int64.toString()); if (num > globalThis.Number.MAX_SAFE_INTEGER) { - throw new globalThis.Error("Value is larger than Number.MAX_SAFE_INTEGER"); + throw new globalThis.Error('Value is larger than Number.MAX_SAFE_INTEGER'); } if (num < globalThis.Number.MIN_SAFE_INTEGER) { - throw new globalThis.Error("Value is smaller than Number.MIN_SAFE_INTEGER"); + throw new globalThis.Error('Value is smaller than Number.MIN_SAFE_INTEGER'); } return num; } diff --git a/sdks/typescript/src/protoc/v1/shared/condition.ts b/sdks/typescript/src/protoc/v1/shared/condition.ts index 7e1bdb74a0..9d7131a178 100644 --- a/sdks/typescript/src/protoc/v1/shared/condition.ts +++ b/sdks/typescript/src/protoc/v1/shared/condition.ts @@ -5,10 +5,10 @@ // source: v1/shared/condition.proto /* eslint-disable */ -import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire"; -import { Timestamp } from "../../google/protobuf/timestamp"; +import { BinaryReader, BinaryWriter } from '@bufbuild/protobuf/wire'; +import { Timestamp } from '../../google/protobuf/timestamp'; -export const protobufPackage = "v1"; +export const protobufPackage = 'v1'; export enum Action { CREATE = 0, @@ -21,19 +21,19 @@ export enum Action { export function actionFromJSON(object: any): Action { switch (object) { case 0: - case "CREATE": + case 'CREATE': return Action.CREATE; case 1: - case "QUEUE": + case 'QUEUE': return Action.QUEUE; case 2: - case "CANCEL": + case 'CANCEL': return Action.CANCEL; case 3: - case "SKIP": + case 'SKIP': return Action.SKIP; case -1: - case "UNRECOGNIZED": + case 'UNRECOGNIZED': default: return Action.UNRECOGNIZED; } @@ -42,16 +42,16 @@ export function actionFromJSON(object: any): Action { export function actionToJSON(object: Action): string { switch (object) { case Action.CREATE: - return "CREATE"; + return 'CREATE'; case Action.QUEUE: - return "QUEUE"; + return 'QUEUE'; case Action.CANCEL: - return "CANCEL"; + return 'CANCEL'; case Action.SKIP: - return "SKIP"; + return 'SKIP'; case Action.UNRECOGNIZED: default: - return "UNRECOGNIZED"; + return 'UNRECOGNIZED'; } } @@ -69,9 +69,7 @@ export interface ParentOverrideMatchCondition { } export interface SleepMatchCondition { - base: - | BaseMatchCondition - | undefined; + base: BaseMatchCondition | undefined; /** a duration string indicating how long to sleep */ sleepFor: string; } @@ -96,21 +94,21 @@ export interface DurableEventListenerConditions { } function createBaseBaseMatchCondition(): BaseMatchCondition { - return { readableDataKey: "", action: 0, orGroupId: "", expression: "" }; + return { readableDataKey: '', action: 0, orGroupId: '', expression: '' }; } export const BaseMatchCondition: MessageFns = { encode(message: BaseMatchCondition, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { - if (message.readableDataKey !== "") { + if (message.readableDataKey !== '') { writer.uint32(10).string(message.readableDataKey); } if (message.action !== 0) { writer.uint32(16).int32(message.action); } - if (message.orGroupId !== "") { + if (message.orGroupId !== '') { writer.uint32(26).string(message.orGroupId); } - if (message.expression !== "") { + if (message.expression !== '') { writer.uint32(34).string(message.expression); } return writer; @@ -169,30 +167,30 @@ export const BaseMatchCondition: MessageFns = { readableDataKey: isSet(object.readableDataKey) ? globalThis.String(object.readableDataKey) : isSet(object.readable_data_key) - ? globalThis.String(object.readable_data_key) - : "", + ? globalThis.String(object.readable_data_key) + : '', action: isSet(object.action) ? actionFromJSON(object.action) : 0, orGroupId: isSet(object.orGroupId) ? globalThis.String(object.orGroupId) : isSet(object.or_group_id) - ? globalThis.String(object.or_group_id) - : "", - expression: isSet(object.expression) ? globalThis.String(object.expression) : "", + ? globalThis.String(object.or_group_id) + : '', + expression: isSet(object.expression) ? globalThis.String(object.expression) : '', }; }, toJSON(message: BaseMatchCondition): unknown { const obj: any = {}; - if (message.readableDataKey !== "") { + if (message.readableDataKey !== '') { obj.readableDataKey = message.readableDataKey; } if (message.action !== 0) { obj.action = actionToJSON(message.action); } - if (message.orGroupId !== "") { + if (message.orGroupId !== '') { obj.orGroupId = message.orGroupId; } - if (message.expression !== "") { + if (message.expression !== '') { obj.expression = message.expression; } return obj; @@ -203,24 +201,27 @@ export const BaseMatchCondition: MessageFns = { }, fromPartial(object: DeepPartial): BaseMatchCondition { const message = createBaseBaseMatchCondition(); - message.readableDataKey = object.readableDataKey ?? ""; + message.readableDataKey = object.readableDataKey ?? ''; message.action = object.action ?? 0; - message.orGroupId = object.orGroupId ?? ""; - message.expression = object.expression ?? ""; + message.orGroupId = object.orGroupId ?? ''; + message.expression = object.expression ?? ''; return message; }, }; function createBaseParentOverrideMatchCondition(): ParentOverrideMatchCondition { - return { base: undefined, parentReadableId: "" }; + return { base: undefined, parentReadableId: '' }; } export const ParentOverrideMatchCondition: MessageFns = { - encode(message: ParentOverrideMatchCondition, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + encode( + message: ParentOverrideMatchCondition, + writer: BinaryWriter = new BinaryWriter() + ): BinaryWriter { if (message.base !== undefined) { BaseMatchCondition.encode(message.base, writer.uint32(10).fork()).join(); } - if (message.parentReadableId !== "") { + if (message.parentReadableId !== '') { writer.uint32(18).string(message.parentReadableId); } return writer; @@ -264,8 +265,8 @@ export const ParentOverrideMatchCondition: MessageFns): ParentOverrideMatchCondition { const message = createBaseParentOverrideMatchCondition(); - message.base = (object.base !== undefined && object.base !== null) - ? BaseMatchCondition.fromPartial(object.base) - : undefined; - message.parentReadableId = object.parentReadableId ?? ""; + message.base = + object.base !== undefined && object.base !== null + ? BaseMatchCondition.fromPartial(object.base) + : undefined; + message.parentReadableId = object.parentReadableId ?? ''; return message; }, }; function createBaseSleepMatchCondition(): SleepMatchCondition { - return { base: undefined, sleepFor: "" }; + return { base: undefined, sleepFor: '' }; } export const SleepMatchCondition: MessageFns = { @@ -302,7 +304,7 @@ export const SleepMatchCondition: MessageFns = { if (message.base !== undefined) { BaseMatchCondition.encode(message.base, writer.uint32(10).fork()).join(); } - if (message.sleepFor !== "") { + if (message.sleepFor !== '') { writer.uint32(18).string(message.sleepFor); } return writer; @@ -346,8 +348,8 @@ export const SleepMatchCondition: MessageFns = { sleepFor: isSet(object.sleepFor) ? globalThis.String(object.sleepFor) : isSet(object.sleep_for) - ? globalThis.String(object.sleep_for) - : "", + ? globalThis.String(object.sleep_for) + : '', }; }, @@ -356,7 +358,7 @@ export const SleepMatchCondition: MessageFns = { if (message.base !== undefined) { obj.base = BaseMatchCondition.toJSON(message.base); } - if (message.sleepFor !== "") { + if (message.sleepFor !== '') { obj.sleepFor = message.sleepFor; } return obj; @@ -367,24 +369,33 @@ export const SleepMatchCondition: MessageFns = { }, fromPartial(object: DeepPartial): SleepMatchCondition { const message = createBaseSleepMatchCondition(); - message.base = (object.base !== undefined && object.base !== null) - ? BaseMatchCondition.fromPartial(object.base) - : undefined; - message.sleepFor = object.sleepFor ?? ""; + message.base = + object.base !== undefined && object.base !== null + ? BaseMatchCondition.fromPartial(object.base) + : undefined; + message.sleepFor = object.sleepFor ?? ''; return message; }, }; function createBaseUserEventMatchCondition(): UserEventMatchCondition { - return { base: undefined, userEventKey: "", eventScope: undefined, considerEventsSince: undefined }; + return { + base: undefined, + userEventKey: '', + eventScope: undefined, + considerEventsSince: undefined, + }; } export const UserEventMatchCondition: MessageFns = { - encode(message: UserEventMatchCondition, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + encode( + message: UserEventMatchCondition, + writer: BinaryWriter = new BinaryWriter() + ): BinaryWriter { if (message.base !== undefined) { BaseMatchCondition.encode(message.base, writer.uint32(10).fork()).join(); } - if (message.userEventKey !== "") { + if (message.userEventKey !== '') { writer.uint32(18).string(message.userEventKey); } if (message.eventScope !== undefined) { @@ -450,18 +461,18 @@ export const UserEventMatchCondition: MessageFns = { userEventKey: isSet(object.userEventKey) ? globalThis.String(object.userEventKey) : isSet(object.user_event_key) - ? globalThis.String(object.user_event_key) - : "", + ? globalThis.String(object.user_event_key) + : '', eventScope: isSet(object.eventScope) ? globalThis.String(object.eventScope) : isSet(object.event_scope) - ? globalThis.String(object.event_scope) - : undefined, + ? globalThis.String(object.event_scope) + : undefined, considerEventsSince: isSet(object.considerEventsSince) ? fromJsonTimestamp(object.considerEventsSince) : isSet(object.consider_events_since) - ? fromJsonTimestamp(object.consider_events_since) - : undefined, + ? fromJsonTimestamp(object.consider_events_since) + : undefined, }; }, @@ -470,7 +481,7 @@ export const UserEventMatchCondition: MessageFns = { if (message.base !== undefined) { obj.base = BaseMatchCondition.toJSON(message.base); } - if (message.userEventKey !== "") { + if (message.userEventKey !== '') { obj.userEventKey = message.userEventKey; } if (message.eventScope !== undefined) { @@ -487,10 +498,11 @@ export const UserEventMatchCondition: MessageFns = { }, fromPartial(object: DeepPartial): UserEventMatchCondition { const message = createBaseUserEventMatchCondition(); - message.base = (object.base !== undefined && object.base !== null) - ? BaseMatchCondition.fromPartial(object.base) - : undefined; - message.userEventKey = object.userEventKey ?? ""; + message.base = + object.base !== undefined && object.base !== null + ? BaseMatchCondition.fromPartial(object.base) + : undefined; + message.userEventKey = object.userEventKey ?? ''; message.eventScope = object.eventScope ?? undefined; message.considerEventsSince = object.considerEventsSince ?? undefined; return message; @@ -527,7 +539,9 @@ export const TaskConditions: MessageFns = { break; } - message.parentOverrideConditions.push(ParentOverrideMatchCondition.decode(reader, reader.uint32())); + message.parentOverrideConditions.push( + ParentOverrideMatchCondition.decode(reader, reader.uint32()) + ); continue; } case 2: { @@ -560,18 +574,20 @@ export const TaskConditions: MessageFns = { parentOverrideConditions: globalThis.Array.isArray(object?.parentOverrideConditions) ? object.parentOverrideConditions.map((e: any) => ParentOverrideMatchCondition.fromJSON(e)) : globalThis.Array.isArray(object?.parent_override_conditions) - ? object.parent_override_conditions.map((e: any) => ParentOverrideMatchCondition.fromJSON(e)) - : [], + ? object.parent_override_conditions.map((e: any) => + ParentOverrideMatchCondition.fromJSON(e) + ) + : [], sleepConditions: globalThis.Array.isArray(object?.sleepConditions) ? object.sleepConditions.map((e: any) => SleepMatchCondition.fromJSON(e)) : globalThis.Array.isArray(object?.sleep_conditions) - ? object.sleep_conditions.map((e: any) => SleepMatchCondition.fromJSON(e)) - : [], + ? object.sleep_conditions.map((e: any) => SleepMatchCondition.fromJSON(e)) + : [], userEventConditions: globalThis.Array.isArray(object?.userEventConditions) ? object.userEventConditions.map((e: any) => UserEventMatchCondition.fromJSON(e)) : globalThis.Array.isArray(object?.user_event_conditions) - ? object.user_event_conditions.map((e: any) => UserEventMatchCondition.fromJSON(e)) - : [], + ? object.user_event_conditions.map((e: any) => UserEventMatchCondition.fromJSON(e)) + : [], }; }, @@ -586,7 +602,9 @@ export const TaskConditions: MessageFns = { obj.sleepConditions = message.sleepConditions.map((e) => SleepMatchCondition.toJSON(e)); } if (message.userEventConditions?.length) { - obj.userEventConditions = message.userEventConditions.map((e) => UserEventMatchCondition.toJSON(e)); + obj.userEventConditions = message.userEventConditions.map((e) => + UserEventMatchCondition.toJSON(e) + ); } return obj; }, @@ -597,9 +615,12 @@ export const TaskConditions: MessageFns = { fromPartial(object: DeepPartial): TaskConditions { const message = createBaseTaskConditions(); message.parentOverrideConditions = - object.parentOverrideConditions?.map((e) => ParentOverrideMatchCondition.fromPartial(e)) || []; - message.sleepConditions = object.sleepConditions?.map((e) => SleepMatchCondition.fromPartial(e)) || []; - message.userEventConditions = object.userEventConditions?.map((e) => UserEventMatchCondition.fromPartial(e)) || []; + object.parentOverrideConditions?.map((e) => ParentOverrideMatchCondition.fromPartial(e)) || + []; + message.sleepConditions = + object.sleepConditions?.map((e) => SleepMatchCondition.fromPartial(e)) || []; + message.userEventConditions = + object.userEventConditions?.map((e) => UserEventMatchCondition.fromPartial(e)) || []; return message; }, }; @@ -609,7 +630,10 @@ function createBaseDurableEventListenerConditions(): DurableEventListenerConditi } export const DurableEventListenerConditions: MessageFns = { - encode(message: DurableEventListenerConditions, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + encode( + message: DurableEventListenerConditions, + writer: BinaryWriter = new BinaryWriter() + ): BinaryWriter { for (const v of message.sleepConditions) { SleepMatchCondition.encode(v!, writer.uint32(10).fork()).join(); } @@ -656,13 +680,13 @@ export const DurableEventListenerConditions: MessageFns SleepMatchCondition.fromJSON(e)) : globalThis.Array.isArray(object?.sleep_conditions) - ? object.sleep_conditions.map((e: any) => SleepMatchCondition.fromJSON(e)) - : [], + ? object.sleep_conditions.map((e: any) => SleepMatchCondition.fromJSON(e)) + : [], userEventConditions: globalThis.Array.isArray(object?.userEventConditions) ? object.userEventConditions.map((e: any) => UserEventMatchCondition.fromJSON(e)) : globalThis.Array.isArray(object?.user_event_conditions) - ? object.user_event_conditions.map((e: any) => UserEventMatchCondition.fromJSON(e)) - : [], + ? object.user_event_conditions.map((e: any) => UserEventMatchCondition.fromJSON(e)) + : [], }; }, @@ -672,7 +696,9 @@ export const DurableEventListenerConditions: MessageFns SleepMatchCondition.toJSON(e)); } if (message.userEventConditions?.length) { - obj.userEventConditions = message.userEventConditions.map((e) => UserEventMatchCondition.toJSON(e)); + obj.userEventConditions = message.userEventConditions.map((e) => + UserEventMatchCondition.toJSON(e) + ); } return obj; }, @@ -682,19 +708,25 @@ export const DurableEventListenerConditions: MessageFns): DurableEventListenerConditions { const message = createBaseDurableEventListenerConditions(); - message.sleepConditions = object.sleepConditions?.map((e) => SleepMatchCondition.fromPartial(e)) || []; - message.userEventConditions = object.userEventConditions?.map((e) => UserEventMatchCondition.fromPartial(e)) || []; + message.sleepConditions = + object.sleepConditions?.map((e) => SleepMatchCondition.fromPartial(e)) || []; + message.userEventConditions = + object.userEventConditions?.map((e) => UserEventMatchCondition.fromPartial(e)) || []; return message; }, }; type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined; -export type DeepPartial = T extends Builtin ? T - : T extends globalThis.Array ? globalThis.Array> - : T extends ReadonlyArray ? ReadonlyArray> - : T extends {} ? { [K in keyof T]?: DeepPartial } - : Partial; +export type DeepPartial = T extends Builtin + ? T + : T extends globalThis.Array + ? globalThis.Array> + : T extends ReadonlyArray + ? ReadonlyArray> + : T extends {} + ? { [K in keyof T]?: DeepPartial } + : Partial; function toTimestamp(date: Date): Timestamp { const seconds = Math.trunc(date.getTime() / 1_000); @@ -711,7 +743,7 @@ function fromTimestamp(t: Timestamp): Date { function fromJsonTimestamp(o: any): Date { if (o instanceof globalThis.Date) { return o; - } else if (typeof o === "string") { + } else if (typeof o === 'string') { return new globalThis.Date(o); } else { return fromTimestamp(Timestamp.fromJSON(o)); From 1ce6e17205c2250d2a78a853cb9c8bd468cea14e Mon Sep 17 00:00:00 2001 From: Hugo martins Date: Wed, 8 Jul 2026 04:07:51 +0200 Subject: [PATCH 4/4] chore: tighten PR diff and fix docs prettier - Revert condition.ts / timestamp.ts to origin/main: their only changes were unrelated protoc v3.19.1->v7.35.1 regeneration churn, not part of the display_name feature. Reverting keeps the PR to just the files that must change (trigger.ts / workflows.ts). Verified tsc + lint:check still pass. - Prettier-fix the child-spawning.mdx Callout block added by this branch. Co-Authored-By: Claude Opus 4.8 (1M context) --- frontend/docs/pages/v1/child-spawning.mdx | 4 ++-- .../src/protoc/google/protobuf/timestamp.ts | 21 +++++++++---------- .../src/protoc/v1/shared/condition.ts | 2 +- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/frontend/docs/pages/v1/child-spawning.mdx b/frontend/docs/pages/v1/child-spawning.mdx index e3e9c3d9e9..0e80264f2e 100644 --- a/frontend/docs/pages/v1/child-spawning.mdx +++ b/frontend/docs/pages/v1/child-spawning.mdx @@ -12,8 +12,8 @@ A task can spawn child tasks at runtime — including other durable tasks or ent Spawning many children at once? Give each a [display name](./run-names.mdx) so - they're identifiable at a glance in the dashboard instead of sharing a generated - name. + they're identifiable at a glance in the dashboard instead of sharing a + generated name. diff --git a/sdks/typescript/src/protoc/google/protobuf/timestamp.ts b/sdks/typescript/src/protoc/google/protobuf/timestamp.ts index f6df430a4d..ee4b6339ba 100644 --- a/sdks/typescript/src/protoc/google/protobuf/timestamp.ts +++ b/sdks/typescript/src/protoc/google/protobuf/timestamp.ts @@ -1,7 +1,7 @@ // Code generated by protoc-gen-ts_proto. DO NOT EDIT. // versions: // protoc-gen-ts_proto v2.11.8 -// protoc v7.35.1 +// protoc v3.19.1 // source: google/protobuf/timestamp.proto /* eslint-disable */ @@ -82,8 +82,8 @@ export const protobufPackage = 'google.protobuf'; * {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional * seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), * are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone - * is required. A ProtoJSON serializer should always use UTC (as indicated by - * "Z") when printing the Timestamp type and a ProtoJSON parser should be + * is required. A proto3 JSON serializer should always use UTC (as indicated by + * "Z") when printing the Timestamp type and a proto3 JSON parser should be * able to accept both UTC and other timezones (as indicated by an offset). * * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past @@ -97,21 +97,20 @@ export const protobufPackage = 'google.protobuf'; * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with * the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use * the Joda Time's [`ISODateTimeFormat.dateTime()`]( - * http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime() + * http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D * ) to obtain a formatter capable of generating timestamps in this format. */ export interface Timestamp { /** - * Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must - * be between -62135596800 and 253402300799 inclusive (which corresponds to - * 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z). + * Represents seconds of UTC time since Unix epoch + * 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to + * 9999-12-31T23:59:59Z inclusive. */ seconds: number; /** - * Non-negative fractions of a second at nanosecond resolution. This field is - * the nanosecond portion of the duration, not an alternative to seconds. - * Negative second values with fractions must still have non-negative nanos - * values that count forward in time. Must be between 0 and 999,999,999 + * Non-negative fractions of a second at nanosecond resolution. Negative + * second values with fractions must still have non-negative nanos values + * that count forward in time. Must be from 0 to 999,999,999 * inclusive. */ nanos: number; diff --git a/sdks/typescript/src/protoc/v1/shared/condition.ts b/sdks/typescript/src/protoc/v1/shared/condition.ts index 9d7131a178..ae8ce105c0 100644 --- a/sdks/typescript/src/protoc/v1/shared/condition.ts +++ b/sdks/typescript/src/protoc/v1/shared/condition.ts @@ -1,7 +1,7 @@ // Code generated by protoc-gen-ts_proto. DO NOT EDIT. // versions: // protoc-gen-ts_proto v2.11.8 -// protoc v7.35.1 +// protoc v3.19.1 // source: v1/shared/condition.proto /* eslint-disable */