@soat/cli 0.62.0 → 0.64.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.mjs +470 -5
  2. package/package.json +3 -3
package/dist/index.mjs CHANGED
@@ -13,7 +13,7 @@ import * as os from "node:os";
13
13
  import { createHmac, timingSafeEqual } from "node:crypto";
14
14
 
15
15
  //#region package.json
16
- var version = "0.62.0";
16
+ var version = "0.64.0";
17
17
 
18
18
  //#endregion
19
19
  //#region src/cli-wrappers/wrappers/formations.ts
@@ -780,6 +780,12 @@ var routes = {
780
780
  "required": true,
781
781
  "type": "string",
782
782
  "in": "path"
783
+ }, {
784
+ "name": "tags",
785
+ "description": "Key-value labels on a resource. A flat object of string values — an array, a nested object or a number is rejected with `400 VALIDATION_FAILED`, never coerced. Keys are opaque and stored verbatim, so `cost_center` and `costCenter` are two different tags. Matched by JSONB containment wherever tags are read: the `?tags=` filter, knowledge search, and the IAM `soat:ResourceTag/<key>` condition.\n\nKeys beginning `system.` are reserved: the platform writes them to record which conversation, actor, agent and role a row came from, and a write naming one is refused with `400 RESERVED_TAG_KEY`. They are read and filtered like any other tag.\n\nThe bag is bounded, because every pair reaches the IAM context of every access check on the resource: at most 50 keys, each key at most 128 characters and each value at most 256. A write past a bound — including a merge that would grow the stored bag past the key count — is `400 VALIDATION_FAILED` with `meta.limit` naming the bound it crossed. `system.*` keys are the platform's and do not count against the 50.",
786
+ "required": true,
787
+ "type": "object",
788
+ "in": "body-root"
783
789
  }]
784
790
  },
785
791
  "merge-actor-tags": {
@@ -798,6 +804,12 @@ var routes = {
798
804
  "required": true,
799
805
  "type": "string",
800
806
  "in": "path"
807
+ }, {
808
+ "name": "tags",
809
+ "description": "Key-value labels on a resource. A flat object of string values — an array, a nested object or a number is rejected with `400 VALIDATION_FAILED`, never coerced. Keys are opaque and stored verbatim, so `cost_center` and `costCenter` are two different tags. Matched by JSONB containment wherever tags are read: the `?tags=` filter, knowledge search, and the IAM `soat:ResourceTag/<key>` condition.\n\nKeys beginning `system.` are reserved: the platform writes them to record which conversation, actor, agent and role a row came from, and a write naming one is refused with `400 RESERVED_TAG_KEY`. They are read and filtered like any other tag.\n\nThe bag is bounded, because every pair reaches the IAM context of every access check on the resource: at most 50 keys, each key at most 128 characters and each value at most 256. A write past a bound — including a merge that would grow the stored bag past the key count — is `400 VALIDATION_FAILED` with `meta.limit` naming the bound it crossed. `system.*` keys are the platform's and do not count against the 50.",
810
+ "required": true,
811
+ "type": "object",
812
+ "in": "body-root"
801
813
  }]
802
814
  },
803
815
  "list-agents": {
@@ -2850,6 +2862,12 @@ var routes = {
2850
2862
  "required": true,
2851
2863
  "type": "string",
2852
2864
  "in": "path"
2865
+ }, {
2866
+ "name": "tags",
2867
+ "description": "Key-value labels on a resource. A flat object of string values — an array, a nested object or a number is rejected with `400 VALIDATION_FAILED`, never coerced. Keys are opaque and stored verbatim, so `cost_center` and `costCenter` are two different tags. Matched by JSONB containment wherever tags are read: the `?tags=` filter, knowledge search, and the IAM `soat:ResourceTag/<key>` condition.\n\nKeys beginning `system.` are reserved: the platform writes them to record which conversation, actor, agent and role a row came from, and a write naming one is refused with `400 RESERVED_TAG_KEY`. They are read and filtered like any other tag.\n\nThe bag is bounded, because every pair reaches the IAM context of every access check on the resource: at most 50 keys, each key at most 128 characters and each value at most 256. A write past a bound — including a merge that would grow the stored bag past the key count — is `400 VALIDATION_FAILED` with `meta.limit` naming the bound it crossed. `system.*` keys are the platform's and do not count against the 50.",
2868
+ "required": true,
2869
+ "type": "object",
2870
+ "in": "body-root"
2853
2871
  }]
2854
2872
  },
2855
2873
  "merge-conversation-tags": {
@@ -2868,6 +2886,378 @@ var routes = {
2868
2886
  "required": true,
2869
2887
  "type": "string",
2870
2888
  "in": "path"
2889
+ }, {
2890
+ "name": "tags",
2891
+ "description": "Key-value labels on a resource. A flat object of string values — an array, a nested object or a number is rejected with `400 VALIDATION_FAILED`, never coerced. Keys are opaque and stored verbatim, so `cost_center` and `costCenter` are two different tags. Matched by JSONB containment wherever tags are read: the `?tags=` filter, knowledge search, and the IAM `soat:ResourceTag/<key>` condition.\n\nKeys beginning `system.` are reserved: the platform writes them to record which conversation, actor, agent and role a row came from, and a write naming one is refused with `400 RESERVED_TAG_KEY`. They are read and filtered like any other tag.\n\nThe bag is bounded, because every pair reaches the IAM context of every access check on the resource: at most 50 keys, each key at most 128 characters and each value at most 256. A write past a bound — including a merge that would grow the stored bag past the key count — is `400 VALIDATION_FAILED` with `meta.limit` naming the bound it crossed. `system.*` keys are the platform's and do not count against the 50.",
2892
+ "required": true,
2893
+ "type": "object",
2894
+ "in": "body-root"
2895
+ }]
2896
+ },
2897
+ "list-deciders": {
2898
+ serviceClass: "Deciders",
2899
+ operationId: "listDeciders",
2900
+ description: "Returns the deciders defined in a project, newest first.",
2901
+ moduleDocsUrl: "https://soat.ttoss.dev/docs/modules/deciders",
2902
+ httpMethod: "get",
2903
+ pathParams: [],
2904
+ queryParams: ["project_id", "limit", "offset"],
2905
+ headerParams: [],
2906
+ cookieParams: [],
2907
+ flags: [{
2908
+ "name": "project_id",
2909
+ "description": "Project ID (required if not using project key auth)",
2910
+ "required": false,
2911
+ "type": "string",
2912
+ "in": "query"
2913
+ }, {
2914
+ "name": "limit",
2915
+ "description": "Maximum number of results to return",
2916
+ "required": false,
2917
+ "type": "integer",
2918
+ "in": "query"
2919
+ }, {
2920
+ "name": "offset",
2921
+ "description": "Number of results to skip",
2922
+ "required": false,
2923
+ "type": "integer",
2924
+ "in": "query"
2925
+ }]
2926
+ },
2927
+ "create-decider": {
2928
+ serviceClass: "Deciders",
2929
+ operationId: "createDecider",
2930
+ description: "Creates a decider at version 1: a named question set and the backend that answers it, exactly one of `agent_id` and `tool_id`. Every question declares a finite answer space, validated here. The backend must be in the decider's project. An agent must carry no tool surface — no tool binding left active by `active_tool_ids` and no `knowledge_config.write_memory_store_id` — or the create is refused with `400 DECIDER_AGENT_NOT_TOOL_LESS`. A tool must be `http` or `pipeline` and must not pin `state` or `questions` in its `preset_parameters`, or the create is refused with `400 DECIDER_TOOL_NOT_CALLABLE`. A duplicate `name` in the project is `409 NAME_CONFLICT`.",
2931
+ moduleDocsUrl: "https://soat.ttoss.dev/docs/modules/deciders",
2932
+ httpMethod: "post",
2933
+ pathParams: [],
2934
+ queryParams: [],
2935
+ headerParams: [],
2936
+ cookieParams: [],
2937
+ flags: [{
2938
+ "name": "project_id",
2939
+ "description": "Project ID (required if not using project key auth)",
2940
+ "required": false,
2941
+ "type": "string",
2942
+ "in": "body"
2943
+ }, {
2944
+ "name": "name",
2945
+ "description": "Human-readable name, unique per project",
2946
+ "required": true,
2947
+ "type": "string",
2948
+ "in": "body"
2949
+ }, {
2950
+ "name": "description",
2951
+ "description": "",
2952
+ "required": false,
2953
+ "type": "string",
2954
+ "in": "body"
2955
+ }, {
2956
+ "name": "agent_id",
2957
+ "description": "A tool-less agent that answers",
2958
+ "required": false,
2959
+ "type": "string",
2960
+ "in": "body"
2961
+ }, {
2962
+ "name": "tool_id",
2963
+ "description": "An http or pipeline tool that answers",
2964
+ "required": false,
2965
+ "type": "string",
2966
+ "in": "body"
2967
+ }, {
2968
+ "name": "questions",
2969
+ "description": "Question id → question, 1 to 20 of them. A question id starts with a letter or underscore and holds only letters, digits and underscores (at most 64), since it keys the answer object.",
2970
+ "required": true,
2971
+ "type": "object",
2972
+ "in": "body"
2973
+ }, {
2974
+ "name": "version_label",
2975
+ "description": "Optional tag for version 1, e.g. `initial`",
2976
+ "required": false,
2977
+ "type": "string",
2978
+ "in": "body"
2979
+ }]
2980
+ },
2981
+ "get-decider": {
2982
+ serviceClass: "Deciders",
2983
+ operationId: "getDecider",
2984
+ description: "Returns a decider with its current question set and version.",
2985
+ moduleDocsUrl: "https://soat.ttoss.dev/docs/modules/deciders",
2986
+ httpMethod: "get",
2987
+ pathParams: ["decider_id"],
2988
+ queryParams: [],
2989
+ headerParams: [],
2990
+ cookieParams: [],
2991
+ flags: [{
2992
+ "name": "decider_id",
2993
+ "description": "The decider ID",
2994
+ "required": true,
2995
+ "type": "string",
2996
+ "in": "path"
2997
+ }]
2998
+ },
2999
+ "update-decider": {
3000
+ serviceClass: "Deciders",
3001
+ operationId: "updateDecider",
3002
+ description: "Updates any of `name`, `description`, the backend and `questions`. Naming `agent_id` or `tool_id` replaces the current backend; naming both is `400`. Only a change to `questions` archives a new version; a rename, a new backend or a rewrite of the questions the decider already holds leaves `version` where it is. A new backend is held to the same rules as on create.",
3003
+ moduleDocsUrl: "https://soat.ttoss.dev/docs/modules/deciders",
3004
+ httpMethod: "patch",
3005
+ pathParams: ["decider_id"],
3006
+ queryParams: [],
3007
+ headerParams: ["If-Match"],
3008
+ cookieParams: [],
3009
+ flags: [{
3010
+ "name": "decider_id",
3011
+ "description": "The decider ID",
3012
+ "required": true,
3013
+ "type": "string",
3014
+ "in": "path"
3015
+ }, {
3016
+ "name": "If-Match",
3017
+ "description": "The version the caller believes the resource holds, as an entity tag (`3` or `\"3\"`). Equivalent to `expected_version` in the request body; `*` states no precondition beyond the resource existing. A mismatch is `409 VERSION_CONFLICT`.",
3018
+ "required": false,
3019
+ "type": "string",
3020
+ "in": "header"
3021
+ }, {
3022
+ "name": "name",
3023
+ "description": "",
3024
+ "required": false,
3025
+ "type": "string",
3026
+ "in": "body"
3027
+ }, {
3028
+ "name": "description",
3029
+ "description": "",
3030
+ "required": false,
3031
+ "type": "string",
3032
+ "in": "body"
3033
+ }, {
3034
+ "name": "agent_id",
3035
+ "description": "Replaces the backend with this agent",
3036
+ "required": false,
3037
+ "type": "string",
3038
+ "in": "body"
3039
+ }, {
3040
+ "name": "tool_id",
3041
+ "description": "Replaces the backend with this tool",
3042
+ "required": false,
3043
+ "type": "string",
3044
+ "in": "body"
3045
+ }, {
3046
+ "name": "questions",
3047
+ "description": "Question id → question, 1 to 20 of them. A question id starts with a letter or underscore and holds only letters, digits and underscores (at most 64), since it keys the answer object.",
3048
+ "required": false,
3049
+ "type": "object",
3050
+ "in": "body"
3051
+ }, {
3052
+ "name": "version_label",
3053
+ "description": "Optional tag for the version this write archives. Ignored when the write changes no question, since no version is archived.",
3054
+ "required": false,
3055
+ "type": "string",
3056
+ "in": "body"
3057
+ }, {
3058
+ "name": "expected_version",
3059
+ "description": "Refuses the write unless the decider is at this version.",
3060
+ "required": false,
3061
+ "type": "integer",
3062
+ "in": "body"
3063
+ }]
3064
+ },
3065
+ "delete-decider": {
3066
+ serviceClass: "Deciders",
3067
+ operationId: "deleteDecider",
3068
+ description: "Deletes a decider and its version archive. Its decisions remain and keep naming the decider's ID.",
3069
+ moduleDocsUrl: "https://soat.ttoss.dev/docs/modules/deciders",
3070
+ httpMethod: "delete",
3071
+ pathParams: ["decider_id"],
3072
+ queryParams: [],
3073
+ headerParams: [],
3074
+ cookieParams: [],
3075
+ flags: [{
3076
+ "name": "decider_id",
3077
+ "description": "The decider ID",
3078
+ "required": true,
3079
+ "type": "string",
3080
+ "in": "path"
3081
+ }]
3082
+ },
3083
+ "list-decider-versions": {
3084
+ serviceClass: "Deciders",
3085
+ operationId: "listDeciderVersions",
3086
+ description: "Returns the decider's archived question sets, newest first. A version is written on create and on every write that changes `questions`.",
3087
+ moduleDocsUrl: "https://soat.ttoss.dev/docs/modules/deciders",
3088
+ httpMethod: "get",
3089
+ pathParams: ["decider_id"],
3090
+ queryParams: ["limit", "offset"],
3091
+ headerParams: [],
3092
+ cookieParams: [],
3093
+ flags: [{
3094
+ "name": "decider_id",
3095
+ "description": "The decider ID",
3096
+ "required": true,
3097
+ "type": "string",
3098
+ "in": "path"
3099
+ }, {
3100
+ "name": "limit",
3101
+ "description": "Maximum number of results to return",
3102
+ "required": false,
3103
+ "type": "integer",
3104
+ "in": "query"
3105
+ }, {
3106
+ "name": "offset",
3107
+ "description": "Number of results to skip",
3108
+ "required": false,
3109
+ "type": "integer",
3110
+ "in": "query"
3111
+ }]
3112
+ },
3113
+ "get-decider-version": {
3114
+ serviceClass: "Deciders",
3115
+ operationId: "getDeciderVersion",
3116
+ description: "Returns the question set a version held. A decision names the `decider_version` it was answered under, so this is how its criteria are read after the decider has changed.",
3117
+ moduleDocsUrl: "https://soat.ttoss.dev/docs/modules/deciders",
3118
+ httpMethod: "get",
3119
+ pathParams: ["decider_id", "version"],
3120
+ queryParams: [],
3121
+ headerParams: [],
3122
+ cookieParams: [],
3123
+ flags: [{
3124
+ "name": "decider_id",
3125
+ "description": "The decider ID",
3126
+ "required": true,
3127
+ "type": "string",
3128
+ "in": "path"
3129
+ }, {
3130
+ "name": "version",
3131
+ "description": "The archived version number",
3132
+ "required": true,
3133
+ "type": "integer",
3134
+ "in": "path"
3135
+ }]
3136
+ },
3137
+ "restore-decider-version": {
3138
+ serviceClass: "Deciders",
3139
+ operationId: "restoreDeciderVersion",
3140
+ description: "Writes an archived question set back as the decider's live one, which archives it again as a new version rather than rewinding the counter. Restoring the question set the decider already holds is a no-op.",
3141
+ moduleDocsUrl: "https://soat.ttoss.dev/docs/modules/deciders",
3142
+ httpMethod: "post",
3143
+ pathParams: ["decider_id", "version"],
3144
+ queryParams: [],
3145
+ headerParams: [],
3146
+ cookieParams: [],
3147
+ flags: [{
3148
+ "name": "decider_id",
3149
+ "description": "The decider ID",
3150
+ "required": true,
3151
+ "type": "string",
3152
+ "in": "path"
3153
+ }, {
3154
+ "name": "version",
3155
+ "description": "The archived version number",
3156
+ "required": true,
3157
+ "type": "integer",
3158
+ "in": "path"
3159
+ }, {
3160
+ "name": "label",
3161
+ "description": "Optional tag for the new version. Defaults to `restored from vN`.",
3162
+ "required": false,
3163
+ "type": "string",
3164
+ "in": "body"
3165
+ }]
3166
+ },
3167
+ "create-decision": {
3168
+ serviceClass: "Deciders",
3169
+ operationId: "createDecision",
3170
+ description: "Evaluates the decider against `state` and records the decision. The questions come from the decider, never from the request, so a call site can only supply what is judged. Everything that can refuse the request is checked before the decision is written, so a refusal is a `4xx` and never a polled failure: the agent's tool surface (`400 DECIDER_AGENT_NOT_TOOL_LESS`), a tool that cannot answer (`400 DECIDER_TOOL_NOT_CALLABLE`), a paused project (`409 PROJECT_PAUSED`) and, for an agent, quota admission (`429 QUOTA_EXCEEDED`). A tool backend is called with `{ state, questions }` and must answer `{ answers: { <question id>: { choice | score | value, probabilities? } } }`; an answer outside that contract fails the decision with `DECISION_ANSWER_INVALID`. With `wait: false`, the default, the answer is `201` with the decision `queued`; poll `GET /api/v1/decisions/{decision_id}` or subscribe to `decisions.completed` and `decisions.failed`. With `wait: true` it is `201` with the decision settled.",
3171
+ moduleDocsUrl: "https://soat.ttoss.dev/docs/modules/deciders",
3172
+ httpMethod: "post",
3173
+ pathParams: ["decider_id"],
3174
+ queryParams: [],
3175
+ headerParams: [],
3176
+ cookieParams: [],
3177
+ flags: [{
3178
+ "name": "decider_id",
3179
+ "description": "The decider ID",
3180
+ "required": true,
3181
+ "type": "string",
3182
+ "in": "path"
3183
+ }, {
3184
+ "name": "state",
3185
+ "description": "What is judged: any JSON value. A string reaches the agent verbatim; anything else is serialized as JSON. Not stored.",
3186
+ "required": true,
3187
+ "type": "unknown",
3188
+ "in": "body"
3189
+ }, {
3190
+ "name": "metadata",
3191
+ "description": "Caller-owned annotations stored on the decision and returned on every read — typically the id of what was judged, since the state itself is not stored. Written once, with the decision. A non-object is rejected with `400 VALIDATION_FAILED` and no decision is written.",
3192
+ "required": false,
3193
+ "type": "object",
3194
+ "in": "body"
3195
+ }, {
3196
+ "name": "wait",
3197
+ "description": "True evaluates before answering and returns the settled decision. False — the default — returns the `queued` decision at once. A `builtin` tool call always waits.",
3198
+ "required": false,
3199
+ "type": "boolean",
3200
+ "in": "body"
3201
+ }]
3202
+ },
3203
+ "list-decisions": {
3204
+ serviceClass: "Deciders",
3205
+ operationId: "listDecisions",
3206
+ description: "Returns the decisions in a project, newest first.",
3207
+ moduleDocsUrl: "https://soat.ttoss.dev/docs/modules/deciders",
3208
+ httpMethod: "get",
3209
+ pathParams: [],
3210
+ queryParams: ["project_id", "decider_id", "status", "limit", "offset"],
3211
+ headerParams: [],
3212
+ cookieParams: [],
3213
+ flags: [{
3214
+ "name": "project_id",
3215
+ "description": "Project ID (required if not using project key auth)",
3216
+ "required": false,
3217
+ "type": "string",
3218
+ "in": "query"
3219
+ }, {
3220
+ "name": "decider_id",
3221
+ "description": "Only decisions requested from this decider",
3222
+ "required": false,
3223
+ "type": "string",
3224
+ "in": "query"
3225
+ }, {
3226
+ "name": "status",
3227
+ "description": "Only decisions in this status",
3228
+ "required": false,
3229
+ "type": "string",
3230
+ "in": "query"
3231
+ }, {
3232
+ "name": "limit",
3233
+ "description": "Maximum number of results to return",
3234
+ "required": false,
3235
+ "type": "integer",
3236
+ "in": "query"
3237
+ }, {
3238
+ "name": "offset",
3239
+ "description": "Number of results to skip",
3240
+ "required": false,
3241
+ "type": "integer",
3242
+ "in": "query"
3243
+ }]
3244
+ },
3245
+ "get-decision": {
3246
+ serviceClass: "Deciders",
3247
+ operationId: "getDecision",
3248
+ description: "Returns a decision. Poll it after a `wait: false` request until `status` is `completed` or `failed`.",
3249
+ moduleDocsUrl: "https://soat.ttoss.dev/docs/modules/deciders",
3250
+ httpMethod: "get",
3251
+ pathParams: ["decision_id"],
3252
+ queryParams: [],
3253
+ headerParams: [],
3254
+ cookieParams: [],
3255
+ flags: [{
3256
+ "name": "decision_id",
3257
+ "description": "The decision ID",
3258
+ "required": true,
3259
+ "type": "string",
3260
+ "in": "path"
2871
3261
  }]
2872
3262
  },
2873
3263
  "list-documents": {
@@ -3504,6 +3894,12 @@ var routes = {
3504
3894
  "required": true,
3505
3895
  "type": "string",
3506
3896
  "in": "path"
3897
+ }, {
3898
+ "name": "tags",
3899
+ "description": "Key-value labels on a resource. A flat object of string values — an array, a nested object or a number is rejected with `400 VALIDATION_FAILED`, never coerced. Keys are opaque and stored verbatim, so `cost_center` and `costCenter` are two different tags. Matched by JSONB containment wherever tags are read: the `?tags=` filter, knowledge search, and the IAM `soat:ResourceTag/<key>` condition.\n\nKeys beginning `system.` are reserved: the platform writes them to record which conversation, actor, agent and role a row came from, and a write naming one is refused with `400 RESERVED_TAG_KEY`. They are read and filtered like any other tag.\n\nThe bag is bounded, because every pair reaches the IAM context of every access check on the resource: at most 50 keys, each key at most 128 characters and each value at most 256. A write past a bound — including a merge that would grow the stored bag past the key count — is `400 VALIDATION_FAILED` with `meta.limit` naming the bound it crossed. `system.*` keys are the platform's and do not count against the 50.",
3900
+ "required": true,
3901
+ "type": "object",
3902
+ "in": "body-root"
3507
3903
  }]
3508
3904
  },
3509
3905
  "merge-document-tags": {
@@ -3522,6 +3918,12 @@ var routes = {
3522
3918
  "required": true,
3523
3919
  "type": "string",
3524
3920
  "in": "path"
3921
+ }, {
3922
+ "name": "tags",
3923
+ "description": "Key-value labels on a resource. A flat object of string values — an array, a nested object or a number is rejected with `400 VALIDATION_FAILED`, never coerced. Keys are opaque and stored verbatim, so `cost_center` and `costCenter` are two different tags. Matched by JSONB containment wherever tags are read: the `?tags=` filter, knowledge search, and the IAM `soat:ResourceTag/<key>` condition.\n\nKeys beginning `system.` are reserved: the platform writes them to record which conversation, actor, agent and role a row came from, and a write naming one is refused with `400 RESERVED_TAG_KEY`. They are read and filtered like any other tag.\n\nThe bag is bounded, because every pair reaches the IAM context of every access check on the resource: at most 50 keys, each key at most 128 characters and each value at most 256. A write past a bound — including a merge that would grow the stored bag past the key count — is `400 VALIDATION_FAILED` with `meta.limit` naming the bound it crossed. `system.*` keys are the platform's and do not count against the 50.",
3924
+ "required": true,
3925
+ "type": "object",
3926
+ "in": "body-root"
3525
3927
  }]
3526
3928
  },
3527
3929
  "create-embeddings": {
@@ -4662,6 +5064,12 @@ var routes = {
4662
5064
  "required": true,
4663
5065
  "type": "string",
4664
5066
  "in": "path"
5067
+ }, {
5068
+ "name": "tags",
5069
+ "description": "Key-value labels on a resource. A flat object of string values — an array, a nested object or a number is rejected with `400 VALIDATION_FAILED`, never coerced. Keys are opaque and stored verbatim, so `cost_center` and `costCenter` are two different tags. Matched by JSONB containment wherever tags are read: the `?tags=` filter, knowledge search, and the IAM `soat:ResourceTag/<key>` condition.\n\nKeys beginning `system.` are reserved: the platform writes them to record which conversation, actor, agent and role a row came from, and a write naming one is refused with `400 RESERVED_TAG_KEY`. They are read and filtered like any other tag.\n\nThe bag is bounded, because every pair reaches the IAM context of every access check on the resource: at most 50 keys, each key at most 128 characters and each value at most 256. A write past a bound — including a merge that would grow the stored bag past the key count — is `400 VALIDATION_FAILED` with `meta.limit` naming the bound it crossed. `system.*` keys are the platform's and do not count against the 50.",
5070
+ "required": true,
5071
+ "type": "object",
5072
+ "in": "body-root"
4665
5073
  }]
4666
5074
  },
4667
5075
  "merge-file-tags": {
@@ -4680,6 +5088,12 @@ var routes = {
4680
5088
  "required": true,
4681
5089
  "type": "string",
4682
5090
  "in": "path"
5091
+ }, {
5092
+ "name": "tags",
5093
+ "description": "Key-value labels on a resource. A flat object of string values — an array, a nested object or a number is rejected with `400 VALIDATION_FAILED`, never coerced. Keys are opaque and stored verbatim, so `cost_center` and `costCenter` are two different tags. Matched by JSONB containment wherever tags are read: the `?tags=` filter, knowledge search, and the IAM `soat:ResourceTag/<key>` condition.\n\nKeys beginning `system.` are reserved: the platform writes them to record which conversation, actor, agent and role a row came from, and a write naming one is refused with `400 RESERVED_TAG_KEY`. They are read and filtered like any other tag.\n\nThe bag is bounded, because every pair reaches the IAM context of every access check on the resource: at most 50 keys, each key at most 128 characters and each value at most 256. A write past a bound — including a merge that would grow the stored bag past the key count — is `400 VALIDATION_FAILED` with `meta.limit` naming the bound it crossed. `system.*` keys are the platform's and do not count against the 50.",
5094
+ "required": true,
5095
+ "type": "object",
5096
+ "in": "body-root"
4683
5097
  }]
4684
5098
  },
4685
5099
  "validate-formation": {
@@ -5988,6 +6402,12 @@ var routes = {
5988
6402
  "required": true,
5989
6403
  "type": "string",
5990
6404
  "in": "path"
6405
+ }, {
6406
+ "name": "tags",
6407
+ "description": "Key-value labels on a resource. A flat object of string values — an array, a nested object or a number is rejected with `400 VALIDATION_FAILED`, never coerced. Keys are opaque and stored verbatim, so `cost_center` and `costCenter` are two different tags. Matched by JSONB containment wherever tags are read: the `?tags=` filter, knowledge search, and the IAM `soat:ResourceTag/<key>` condition.\n\nKeys beginning `system.` are reserved: the platform writes them to record which conversation, actor, agent and role a row came from, and a write naming one is refused with `400 RESERVED_TAG_KEY`. They are read and filtered like any other tag.\n\nThe bag is bounded, because every pair reaches the IAM context of every access check on the resource: at most 50 keys, each key at most 128 characters and each value at most 256. A write past a bound — including a merge that would grow the stored bag past the key count — is `400 VALIDATION_FAILED` with `meta.limit` naming the bound it crossed. `system.*` keys are the platform's and do not count against the 50.",
6408
+ "required": true,
6409
+ "type": "object",
6410
+ "in": "body-root"
5991
6411
  }]
5992
6412
  },
5993
6413
  "merge-memory-tags": {
@@ -6006,6 +6426,12 @@ var routes = {
6006
6426
  "required": true,
6007
6427
  "type": "string",
6008
6428
  "in": "path"
6429
+ }, {
6430
+ "name": "tags",
6431
+ "description": "Key-value labels on a resource. A flat object of string values — an array, a nested object or a number is rejected with `400 VALIDATION_FAILED`, never coerced. Keys are opaque and stored verbatim, so `cost_center` and `costCenter` are two different tags. Matched by JSONB containment wherever tags are read: the `?tags=` filter, knowledge search, and the IAM `soat:ResourceTag/<key>` condition.\n\nKeys beginning `system.` are reserved: the platform writes them to record which conversation, actor, agent and role a row came from, and a write naming one is refused with `400 RESERVED_TAG_KEY`. They are read and filtered like any other tag.\n\nThe bag is bounded, because every pair reaches the IAM context of every access check on the resource: at most 50 keys, each key at most 128 characters and each value at most 256. A write past a bound — including a merge that would grow the stored bag past the key count — is `400 VALIDATION_FAILED` with `meta.limit` naming the bound it crossed. `system.*` keys are the platform's and do not count against the 50.",
6432
+ "required": true,
6433
+ "type": "object",
6434
+ "in": "body-root"
6009
6435
  }]
6010
6436
  },
6011
6437
  "list-memory-rules": {
@@ -6522,6 +6948,12 @@ var routes = {
6522
6948
  "required": true,
6523
6949
  "type": "string",
6524
6950
  "in": "path"
6951
+ }, {
6952
+ "name": "tags",
6953
+ "description": "Key-value labels on a resource. A flat object of string values — an array, a nested object or a number is rejected with `400 VALIDATION_FAILED`, never coerced. Keys are opaque and stored verbatim, so `cost_center` and `costCenter` are two different tags. Matched by JSONB containment wherever tags are read: the `?tags=` filter, knowledge search, and the IAM `soat:ResourceTag/<key>` condition.\n\nKeys beginning `system.` are reserved: the platform writes them to record which conversation, actor, agent and role a row came from, and a write naming one is refused with `400 RESERVED_TAG_KEY`. They are read and filtered like any other tag.\n\nThe bag is bounded, because every pair reaches the IAM context of every access check on the resource: at most 50 keys, each key at most 128 characters and each value at most 256. A write past a bound — including a merge that would grow the stored bag past the key count — is `400 VALIDATION_FAILED` with `meta.limit` naming the bound it crossed. `system.*` keys are the platform's and do not count against the 50.",
6954
+ "required": true,
6955
+ "type": "object",
6956
+ "in": "body-root"
6525
6957
  }]
6526
6958
  },
6527
6959
  "merge-memory-store-tags": {
@@ -6540,6 +6972,12 @@ var routes = {
6540
6972
  "required": true,
6541
6973
  "type": "string",
6542
6974
  "in": "path"
6975
+ }, {
6976
+ "name": "tags",
6977
+ "description": "Key-value labels on a resource. A flat object of string values — an array, a nested object or a number is rejected with `400 VALIDATION_FAILED`, never coerced. Keys are opaque and stored verbatim, so `cost_center` and `costCenter` are two different tags. Matched by JSONB containment wherever tags are read: the `?tags=` filter, knowledge search, and the IAM `soat:ResourceTag/<key>` condition.\n\nKeys beginning `system.` are reserved: the platform writes them to record which conversation, actor, agent and role a row came from, and a write naming one is refused with `400 RESERVED_TAG_KEY`. They are read and filtered like any other tag.\n\nThe bag is bounded, because every pair reaches the IAM context of every access check on the resource: at most 50 keys, each key at most 128 characters and each value at most 256. A write past a bound — including a merge that would grow the stored bag past the key count — is `400 VALIDATION_FAILED` with `meta.limit` naming the bound it crossed. `system.*` keys are the platform's and do not count against the 50.",
6978
+ "required": true,
6979
+ "type": "object",
6980
+ "in": "body-root"
6543
6981
  }]
6544
6982
  },
6545
6983
  "list-metadata-schemas": {
@@ -8520,6 +8958,12 @@ var routes = {
8520
8958
  "required": true,
8521
8959
  "type": "string",
8522
8960
  "in": "path"
8961
+ }, {
8962
+ "name": "tags",
8963
+ "description": "Key-value labels on a resource. A flat object of string values — an array, a nested object or a number is rejected with `400 VALIDATION_FAILED`, never coerced. Keys are opaque and stored verbatim, so `cost_center` and `costCenter` are two different tags. Matched by JSONB containment wherever tags are read: the `?tags=` filter, knowledge search, and the IAM `soat:ResourceTag/<key>` condition.\n\nKeys beginning `system.` are reserved: the platform writes them to record which conversation, actor, agent and role a row came from, and a write naming one is refused with `400 RESERVED_TAG_KEY`. They are read and filtered like any other tag.\n\nThe bag is bounded, because every pair reaches the IAM context of every access check on the resource: at most 50 keys, each key at most 128 characters and each value at most 256. A write past a bound — including a merge that would grow the stored bag past the key count — is `400 VALIDATION_FAILED` with `meta.limit` naming the bound it crossed. `system.*` keys are the platform's and do not count against the 50.",
8964
+ "required": true,
8965
+ "type": "object",
8966
+ "in": "body-root"
8523
8967
  }]
8524
8968
  },
8525
8969
  "merge-session-tags": {
@@ -8538,6 +8982,12 @@ var routes = {
8538
8982
  "required": true,
8539
8983
  "type": "string",
8540
8984
  "in": "path"
8985
+ }, {
8986
+ "name": "tags",
8987
+ "description": "Key-value labels on a resource. A flat object of string values — an array, a nested object or a number is rejected with `400 VALIDATION_FAILED`, never coerced. Keys are opaque and stored verbatim, so `cost_center` and `costCenter` are two different tags. Matched by JSONB containment wherever tags are read: the `?tags=` filter, knowledge search, and the IAM `soat:ResourceTag/<key>` condition.\n\nKeys beginning `system.` are reserved: the platform writes them to record which conversation, actor, agent and role a row came from, and a write naming one is refused with `400 RESERVED_TAG_KEY`. They are read and filtered like any other tag.\n\nThe bag is bounded, because every pair reaches the IAM context of every access check on the resource: at most 50 keys, each key at most 128 characters and each value at most 256. A write past a bound — including a merge that would grow the stored bag past the key count — is `400 VALIDATION_FAILED` with `meta.limit` naming the bound it crossed. `system.*` keys are the platform's and do not count against the 50.",
8988
+ "required": true,
8989
+ "type": "object",
8990
+ "in": "body-root"
8541
8991
  }]
8542
8992
  },
8543
8993
  "list-tasks": {
@@ -9071,7 +9521,7 @@ var routes = {
9071
9521
  "delete-tool": {
9072
9522
  serviceClass: "Tools",
9073
9523
  operationId: "deleteTool",
9074
- description: "Deletes a tool by ID.",
9524
+ description: "Deletes a tool by ID. A tool that is a decider's backend is refused with `409 TOOL_HAS_DEPENDENTS`.",
9075
9525
  moduleDocsUrl: "https://soat.ttoss.dev/docs/modules/tools",
9076
9526
  httpMethod: "delete",
9077
9527
  pathParams: ["tool_id"],
@@ -9674,7 +10124,7 @@ var routes = {
9674
10124
  "in": "query"
9675
10125
  }, {
9676
10126
  "name": "source",
9677
- "description": "Filter by what the spend was incurred for. `eval` is an eval run's item generations, `eval_judge` an `llm_judge` scorer's own completion and `eval_scorer` a `tool` scorer's call, so verification spend is `source` in (`eval`, `eval_judge`, `eval_scorer`); `embedding` is any embedding call. Ordinary agent traffic carries no source and is matched by none of them.\n",
10127
+ "description": "Filter by what the spend was incurred for. `eval` is an eval run's item generations, `eval_judge` an `llm_judge` scorer's own completion and `eval_scorer` a `tool` scorer's call, so verification spend is `source` in (`eval`, `eval_judge`, `eval_scorer`); `decider` is a decision's evaluation; `embedding` is any embedding call. Ordinary agent traffic carries no source and is matched by none of them.\n",
9678
10128
  "required": false,
9679
10129
  "type": "string",
9680
10130
  "in": "query"
@@ -9794,7 +10244,7 @@ var routes = {
9794
10244
  "in": "query"
9795
10245
  }, {
9796
10246
  "name": "source",
9797
- "description": "Narrow by what the spend was incurred for — `eval` and `eval_judge` are verification spend. Ordinary traffic carries no source, so it cannot be selected by this filter; omit the filter for everything.\n",
10247
+ "description": "Narrow by what the spend was incurred for — `eval` and `eval_judge` are verification spend, `decider` is decision spend. Ordinary traffic carries no source, so it cannot be selected by this filter; omit the filter for everything.\n",
9798
10248
  "required": false,
9799
10249
  "type": "string",
9800
10250
  "in": "query"
@@ -11071,6 +11521,10 @@ program.argument("[command]", "API command in kebab-case (e.g. list-actors)").ar
11071
11521
  const pathArgs = {};
11072
11522
  const queryArgs = {};
11073
11523
  const bodyArgs = {};
11524
+ const rootBodyFlag = route.flags.find(f => {
11525
+ return f.in === "body-root";
11526
+ });
11527
+ let rootBody;
11074
11528
  for (const [flagKey, val] of Object.entries(flags)) {
11075
11529
  if (flagKey === "profile" || flagKey === "id") continue;
11076
11530
  const canonical = toCanonical(flagKey);
@@ -11082,7 +11536,9 @@ program.argument("[command]", "API command in kebab-case (e.g. list-actors)").ar
11082
11536
  const queryParam = route.queryParams.find(p => {
11083
11537
  return toCanonical(p) === canonical;
11084
11538
  });
11085
- if (pathParam) pathArgs[pathParam] = parsedValue;else if (queryParam) queryArgs[queryParam] = parsedValue;else if (route.httpMethod === "get") queryArgs[kebabToSnake(flagKey)] = parsedValue;else bodyArgs[kebabToSnake(flagKey)] = parsedValue;
11539
+ if (pathParam) pathArgs[pathParam] = parsedValue;else if (rootBodyFlag && canonical === toCanonical(rootBodyFlag.name)) rootBody = {
11540
+ value: parsedValue
11541
+ };else if (queryParam) queryArgs[queryParam] = parsedValue;else if (route.httpMethod === "get") queryArgs[kebabToSnake(flagKey)] = parsedValue;else bodyArgs[kebabToSnake(flagKey)] = parsedValue;
11086
11542
  }
11087
11543
  const positionalArgs = extractPositionalArgs({
11088
11544
  cliArgs: rawArgs
@@ -11116,6 +11572,15 @@ program.argument("[command]", "API command in kebab-case (e.g. list-actors)").ar
11116
11572
  if (Object.keys(pathArgs).length) callOpts["path"] = pathArgs;
11117
11573
  if (Object.keys(queryArgs).length) callOpts["query"] = queryArgs;
11118
11574
  if (Object.keys(bodyArgs).length) callOpts["body"] = bodyArgs;
11575
+ if (rootBody) {
11576
+ if (Object.keys(bodyArgs).length) {
11577
+ console.error(`Unknown flag(s) ${Object.keys(bodyArgs).map(key => {
11578
+ return `--${toKebab(key)}`;
11579
+ }).join(", ")}: '${commandName}' sends its whole body in --${toKebab(rootBodyFlag?.name ?? "")}.`);
11580
+ process.exit(1);
11581
+ }
11582
+ callOpts["body"] = rootBody.value;
11583
+ }
11119
11584
  const result = await method(callOpts);
11120
11585
  if (result.error) {
11121
11586
  const status = result.response && "status" in result.response ? result.response.status : void 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soat/cli",
3
- "version": "0.62.0",
3
+ "version": "0.64.0",
4
4
  "description": "CLI for SOAT — open-source infrastructure for production-ready AI agents.",
5
5
  "keywords": [
6
6
  "ai-agents",
@@ -22,14 +22,14 @@
22
22
  "dependencies": {
23
23
  "@inquirer/input": "^5.1.6",
24
24
  "@inquirer/password": "^5.2.2",
25
- "@soat/sdk": "0.62.0",
25
+ "@soat/sdk": "0.64.0",
26
26
  "@ttoss/logger": "^0.8.20",
27
27
  "commander": "^15.0.0",
28
28
  "js-yaml": "^5.4.2"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@ttoss/config": "^1.38.0",
32
- "@ttoss/openapi-codegen": "^0.4.0",
32
+ "@ttoss/openapi-codegen": "^0.5.0",
33
33
  "@ttoss/test-utils": "^4.2.19",
34
34
  "@types/jest": "^30.0.0",
35
35
  "@types/node": "^26.5.1",