@vertesia/common 1.4.0-dev.20260615.051508Z → 1.4.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 (100) hide show
  1. package/lib/access-control.d.ts +2 -6
  2. package/lib/access-control.d.ts.map +1 -1
  3. package/lib/access-control.js +3 -0
  4. package/lib/access-control.js.map +1 -1
  5. package/lib/apikey.d.ts +4 -5
  6. package/lib/apikey.d.ts.map +1 -1
  7. package/lib/apikey.js.map +1 -1
  8. package/lib/apps.d.ts +15 -275
  9. package/lib/apps.d.ts.map +1 -1
  10. package/lib/apps.js.map +1 -1
  11. package/lib/ask-user.d.ts +29 -1
  12. package/lib/ask-user.d.ts.map +1 -1
  13. package/lib/data-platform.d.ts +33 -121
  14. package/lib/data-platform.d.ts.map +1 -1
  15. package/lib/data-platform.js.map +1 -1
  16. package/lib/environment.d.ts +11 -1
  17. package/lib/environment.d.ts.map +1 -1
  18. package/lib/environment.js.map +1 -1
  19. package/lib/index.d.ts +1 -1
  20. package/lib/index.d.ts.map +1 -1
  21. package/lib/index.js +1 -1
  22. package/lib/index.js.map +1 -1
  23. package/lib/interaction.d.ts +11 -7
  24. package/lib/interaction.d.ts.map +1 -1
  25. package/lib/interaction.js.map +1 -1
  26. package/lib/json-schema.d.ts +1 -1
  27. package/lib/json-schema.d.ts.map +1 -1
  28. package/lib/oauth-scopes.d.ts +5 -0
  29. package/lib/oauth-scopes.d.ts.map +1 -1
  30. package/lib/oauth-scopes.js +10 -1
  31. package/lib/oauth-scopes.js.map +1 -1
  32. package/lib/oauth-server.d.ts +17 -0
  33. package/lib/oauth-server.d.ts.map +1 -1
  34. package/lib/project.d.ts +1 -1
  35. package/lib/project.d.ts.map +1 -1
  36. package/lib/project.js +26 -26
  37. package/lib/project.js.map +1 -1
  38. package/lib/roles/types.d.ts +54 -0
  39. package/lib/roles/types.d.ts.map +1 -0
  40. package/lib/roles/types.js +17 -0
  41. package/lib/roles/types.js.map +1 -0
  42. package/lib/store/agent-approval.d.ts +18 -0
  43. package/lib/store/agent-approval.d.ts.map +1 -0
  44. package/lib/store/agent-approval.js +11 -0
  45. package/lib/store/agent-approval.js.map +1 -0
  46. package/lib/store/agent-run.d.ts +18 -4
  47. package/lib/store/agent-run.d.ts.map +1 -1
  48. package/lib/store/conversation-state.d.ts +54 -30
  49. package/lib/store/conversation-state.d.ts.map +1 -1
  50. package/lib/store/conversation-state.js +0 -3
  51. package/lib/store/conversation-state.js.map +1 -1
  52. package/lib/store/index.d.ts +1 -0
  53. package/lib/store/index.d.ts.map +1 -1
  54. package/lib/store/index.js +1 -0
  55. package/lib/store/index.js.map +1 -1
  56. package/lib/store/signals.d.ts +15 -0
  57. package/lib/store/signals.d.ts.map +1 -1
  58. package/lib/store/workflow.d.ts +41 -2
  59. package/lib/store/workflow.d.ts.map +1 -1
  60. package/lib/store/workflow.js +8 -5
  61. package/lib/store/workflow.js.map +1 -1
  62. package/lib/sts-token-types.d.ts +2 -2
  63. package/lib/sts-token-types.d.ts.map +1 -1
  64. package/lib/transient-tokens.d.ts +2 -2
  65. package/lib/transient-tokens.d.ts.map +1 -1
  66. package/lib/user.d.ts +2 -2
  67. package/lib/user.d.ts.map +1 -1
  68. package/lib/vertesia-common.js +1 -1
  69. package/lib/vertesia-common.js.map +1 -1
  70. package/package.json +7 -6
  71. package/src/access-control.ts +5 -6
  72. package/src/apikey.ts +4 -5
  73. package/src/apps.ts +15 -298
  74. package/src/ask-user.ts +31 -1
  75. package/src/data-platform.ts +35 -129
  76. package/src/environment.ts +12 -1
  77. package/src/index.ts +1 -1
  78. package/src/interaction.ts +13 -7
  79. package/src/json-schema.ts +1 -0
  80. package/src/oauth-scopes.ts +13 -1
  81. package/src/oauth-server.ts +17 -0
  82. package/src/project.ts +8 -8
  83. package/src/roles/types.ts +58 -0
  84. package/src/store/agent-approval.test.ts +18 -0
  85. package/src/store/agent-approval.ts +33 -0
  86. package/src/store/agent-run.ts +20 -3
  87. package/src/store/conversation-state.ts +62 -36
  88. package/src/store/index.ts +1 -0
  89. package/src/store/signals.ts +16 -0
  90. package/src/store/workflow.test.ts +60 -0
  91. package/src/store/workflow.ts +51 -7
  92. package/src/sts-token-types.ts +2 -2
  93. package/src/transient-tokens.ts +2 -2
  94. package/src/user.ts +2 -2
  95. package/lib/roles.d.ts +0 -19
  96. package/lib/roles.d.ts.map +0 -1
  97. package/lib/roles.js +0 -228
  98. package/lib/roles.js.map +0 -1
  99. package/src/roles.test.ts +0 -30
  100. package/src/roles.ts +0 -251
@@ -79,6 +79,8 @@ export interface DataColumn {
79
79
  default?: string;
80
80
  /** Whether this is the primary key */
81
81
  primary_key?: boolean;
82
+ /** Whether this column should use a sequence-backed auto-increment default */
83
+ auto_increment?: boolean;
82
84
  /** Whether values must be unique */
83
85
  unique?: boolean;
84
86
  /** Semantic type for AI understanding */
@@ -516,6 +518,32 @@ export interface QueryPayload {
516
518
  version_id?: string;
517
519
  }
518
520
 
521
+ /**
522
+ * Payload for mutating data rows with a single SQL statement.
523
+ */
524
+ export interface DataStoreMutateRowsPayload {
525
+ /** SQL statement. Only UPDATE and DELETE statements are accepted. */
526
+ sql: string;
527
+ /** Commit message recorded on the resulting data store version. */
528
+ message: string;
529
+ /** Allow UPDATE/DELETE statements without a WHERE clause. Defaults to false. */
530
+ allow_full_table?: boolean;
531
+ }
532
+
533
+ /**
534
+ * Result from mutating rows in a data store.
535
+ */
536
+ export interface DataStoreMutateRowsResult {
537
+ /** Resulting data store version ID */
538
+ version_id: string;
539
+ /** Tables affected by the statement */
540
+ affected_tables: string[];
541
+ /** Current row counts for affected tables after the mutation */
542
+ row_counts: Record<string, number>;
543
+ /** Statement execution time in milliseconds */
544
+ execution_time_ms: number;
545
+ }
546
+
519
547
  /**
520
548
  * Column metadata in query results.
521
549
  */
@@ -629,6 +657,8 @@ export interface DataColumnForAI {
629
657
  nullable: boolean;
630
658
  /** Whether primary key */
631
659
  primary_key: boolean;
660
+ /** Whether sequence-backed auto-increment is enabled */
661
+ auto_increment: boolean;
632
662
  /** Example values */
633
663
  examples?: string[];
634
664
  }
@@ -821,99 +851,6 @@ export interface DashboardQueryParameters {
821
851
  defaults: Record<string, string>;
822
852
  }
823
853
 
824
- /**
825
- * Elasticsearch DSL supported by dashboard data sources.
826
- * Queries execute through Vertesia Store, so project/security filtering remains server-side.
827
- */
828
- export interface DashboardElasticsearchDsl {
829
- query?: Record<string, unknown>;
830
- aggs?: Record<string, unknown>;
831
- size?: number;
832
- from?: number;
833
- sort?: Array<Record<string, unknown>>;
834
- }
835
-
836
- /**
837
- * How an Elasticsearch DSL result should be converted into Vega rows.
838
- */
839
- export type DashboardElasticsearchResultMapping =
840
- | {
841
- type: 'hits';
842
- }
843
- | {
844
- type: 'aggregation_buckets';
845
- /** Dot path under `aggregations` that contains a `buckets` array. */
846
- path: string;
847
- /** Output field name for bucket key. Defaults to `key`. */
848
- keyField?: string;
849
- /** Output field name for doc count. Defaults to `doc_count`. */
850
- countField?: string;
851
- };
852
-
853
- /**
854
- * Dashboard data source backed by a Data Platform SQL query.
855
- */
856
- export interface DashboardSqlDataSource {
857
- kind: 'data_sql';
858
- /** SQL query that returns all rows for the dashboard. */
859
- query: string;
860
- /** Maximum rows to return from the query. */
861
- queryLimit?: number;
862
- /** Default values for SQL {{param}} placeholders. */
863
- queryParameters?: Record<string, string>;
864
- }
865
-
866
- /**
867
- * Dashboard data source backed by Vertesia Store Elasticsearch DSL.
868
- */
869
- export interface DashboardStoreElasticsearchDataSource {
870
- kind: 'store_es_dsl';
871
- /** Elasticsearch DSL query executed through the secured Store query API. */
872
- dsl: DashboardElasticsearchDsl;
873
- /** Result mapping. Defaults to `hits`. */
874
- result?: DashboardElasticsearchResultMapping;
875
- }
876
-
877
- /**
878
- * Data source for a Vega dashboard.
879
- */
880
- export type DashboardDataSource = DashboardSqlDataSource | DashboardStoreElasticsearchDataSource;
881
-
882
- /**
883
- * Dashboard definition contributed by an app package.
884
- *
885
- * App dashboard IDs are local to the app. The platform exposes them as
886
- * `app:<app_name>:<id>` when listing or retrieving dashboards.
887
- */
888
- export interface AppDashboardDefinition {
889
- /** Local app dashboard ID. */
890
- id: string;
891
- /** Machine-friendly dashboard name. Defaults to `id`. */
892
- name?: string;
893
- /** Display title. Defaults to `name` or `id`. */
894
- title?: string;
895
- /** User-facing description. */
896
- description?: string;
897
- /** Tags for discovery and filtering. */
898
- tags?: string[];
899
- /** Data source used to populate Vega `data.values`. */
900
- dataSource?: DashboardDataSource;
901
- /** SQL query shortcut for app dashboards backed by data stores. */
902
- query?: string;
903
- /** Maximum SQL rows to return. */
904
- queryLimit?: number;
905
- /** Default values for SQL {{param}} placeholders. */
906
- queryParameters?: Record<string, string>;
907
- /** Complete Vega-Lite specification for the dashboard. */
908
- spec?: Record<string, unknown>;
909
- /** Legacy named SQL queries. */
910
- queries?: DashboardQuery[];
911
- /** Legacy panel definitions. */
912
- panels?: DashboardPanel[];
913
- /** Legacy dashboard layout. */
914
- layout?: DashboardLayout;
915
- }
916
-
917
854
  /**
918
855
  * Summary view of a dashboard (for listings).
919
856
  */
@@ -930,22 +867,15 @@ export interface DashboardItem extends BaseObject {
930
867
  last_rendered_at?: string;
931
868
  /** Tags for organization */
932
869
  tags: string[];
933
- /** Source of the dashboard definition. Defaults to stored dashboards. */
934
- source?: 'stored' | 'app';
935
- /** App name when `source` is `app`. */
936
- app_name?: string;
937
- /** App dashboards are read-only until cloned into a stored dashboard. */
938
- readonly?: boolean;
939
870
  }
940
871
 
941
872
  /**
942
873
  * Full dashboard with SQL query and Vega-Lite specification.
943
874
  *
944
875
  * **New architecture (v2):**
945
- * - `dataSource` field with either SQL or Store Elasticsearch DSL
876
+ * - Single `query` field with SQL (use JOINs/CTEs for complex data needs)
946
877
  * - Single `spec` field with complete Vega-Lite spec (vconcat/hconcat for multiple panels)
947
878
  * - Cross-panel interactivity via Vega selections
948
- * - Legacy top-level `query` fields are treated as a SQL data source
949
879
  *
950
880
  * **Legacy architecture (v1, deprecated):**
951
881
  * - Multiple `queries` with named data sources
@@ -955,26 +885,18 @@ export interface DashboardItem extends BaseObject {
955
885
  */
956
886
  export interface Dashboard extends DashboardItem {
957
887
  // ============= New architecture (v2) =============
958
- /**
959
- * Data source used to populate Vega `data.values`.
960
- * When omitted, top-level `query` is treated as a SQL data source for backwards compatibility.
961
- */
962
- dataSource?: DashboardDataSource;
963
888
  /**
964
889
  * SQL query that returns all data for the dashboard.
965
890
  * Use JOINs, CTEs, or UNION ALL to combine data from multiple tables.
966
891
  * Can include {{param_name}} placeholders for dynamic values.
967
- * @deprecated Use `dataSource: { kind: 'data_sql', query }` instead.
968
892
  */
969
893
  query?: string;
970
894
  /**
971
895
  * Maximum rows to return from the query (default: 10000).
972
- * @deprecated Use `dataSource.queryLimit` instead.
973
896
  */
974
897
  queryLimit?: number;
975
898
  /**
976
899
  * Default values for SQL parameters.
977
- * @deprecated Use `dataSource.queryParameters` instead.
978
900
  */
979
901
  queryParameters?: Record<string, string>;
980
902
  /**
@@ -1008,17 +930,15 @@ export interface Dashboard extends DashboardItem {
1008
930
 
1009
931
  /**
1010
932
  * Payload for creating a new dashboard.
1011
- * Requires a data source and spec (Vega-Lite).
933
+ * Requires query (SQL) and spec (Vega-Lite).
1012
934
  */
1013
935
  export interface CreateDashboardPayload {
1014
936
  /** Dashboard name (unique within store) */
1015
937
  name: string;
1016
938
  /** Dashboard summary */
1017
939
  summary?: string;
1018
- /** Data source used to populate Vega `data.values`. */
1019
- dataSource?: DashboardDataSource;
1020
- /** SQL query that returns all data for the dashboard. Deprecated shortcut for a SQL data source. */
1021
- query?: string;
940
+ /** SQL query that returns all data for the dashboard */
941
+ query: string;
1022
942
  /** Maximum rows to return from the query (default: 10000) */
1023
943
  queryLimit?: number;
1024
944
  /** Default values for SQL {{param}} placeholders */
@@ -1035,9 +955,7 @@ export interface UpdateDashboardPayload {
1035
955
  name?: string;
1036
956
  /** Dashboard summary */
1037
957
  summary?: string;
1038
- /** Data source used to populate Vega `data.values`. */
1039
- dataSource?: DashboardDataSource;
1040
- /** SQL query that returns all data for the dashboard. Deprecated shortcut for a SQL data source. */
958
+ /** SQL query that returns all data for the dashboard */
1041
959
  query?: string;
1042
960
  /** Maximum rows to return from the query (default: 10000) */
1043
961
  queryLimit?: number;
@@ -1054,8 +972,6 @@ export interface UpdateDashboardPayload {
1054
972
  */
1055
973
  export interface PreviewDashboardPayload {
1056
974
  // ============= New architecture (v2) =============
1057
- /** Data source used to populate Vega `data.values`. */
1058
- dataSource?: DashboardDataSource;
1059
975
  /** SQL query that returns all data for the dashboard */
1060
976
  query?: string;
1061
977
  /** Maximum rows to return from the query (default: 10000) */
@@ -1119,16 +1035,6 @@ export interface DashboardVersion {
1119
1035
  version_number: number;
1120
1036
  /** Commit message describing the change */
1121
1037
  message: string;
1122
- /** Snapshot of v2 data source at this version */
1123
- dataSource?: DashboardDataSource;
1124
- /** Snapshot of v2 SQL query at this version */
1125
- query?: string;
1126
- /** Snapshot of v2 query limit at this version */
1127
- queryLimit?: number;
1128
- /** Snapshot of v2 query parameters at this version */
1129
- queryParameters?: Record<string, string>;
1130
- /** Snapshot of v2 Vega-Lite spec at this version */
1131
- spec?: Record<string, unknown>;
1132
1038
  /** Snapshot of queries at this version */
1133
1039
  queries: DashboardQuery[];
1134
1040
  /** Snapshot of panels at this version */
@@ -1,4 +1,4 @@
1
- import type { AIModel, ProviderParams, TextFallbackOptions } from '@llumiverse/common';
1
+ import type { AIModel, ProviderParams } from '@llumiverse/common';
2
2
  import { ProviderList, Providers } from '@llumiverse/common';
3
3
 
4
4
  // Virtual providers from studio
@@ -77,6 +77,17 @@ export interface MediatorEnvConfig {
77
77
  model_options?: TextFallbackOptions;
78
78
  }
79
79
 
80
+ export interface TextFallbackOptions {
81
+ _option_id: 'text-fallback';
82
+ max_tokens?: number;
83
+ temperature?: number;
84
+ top_p?: number;
85
+ top_k?: number;
86
+ presence_penalty?: number;
87
+ frequency_penalty?: number;
88
+ stop_sequence?: string[];
89
+ }
90
+
80
91
  export interface ExecutionEnvironmentSettings {
81
92
  [key: string]: unknown;
82
93
  bucket_access_principal?: string;
package/src/index.ts CHANGED
@@ -33,7 +33,7 @@ export * from './prompt.js';
33
33
  export * from './query.js';
34
34
  export * from './rate-limiter.js';
35
35
  export * from './refs.js';
36
- export * from './roles.js';
36
+ export * from './roles/types.js';
37
37
  export * from './runs.js';
38
38
  export * from './secrets.js';
39
39
  export * from './skill.js';
@@ -25,7 +25,8 @@ import type {
25
25
  TemplateType,
26
26
  } from './prompt.js';
27
27
  import type { ExecutionRunDocRef } from './runs.js';
28
- import type { ConversationState, TextArtifactReference } from './store/conversation-state.js';
28
+ import type { AgentToolApprovalMode } from './store/agent-approval.js';
29
+ import type { ConversationState } from './store/conversation-state.js';
29
30
  import type { AccountRef } from './user.js';
30
31
  import type { LlmCallType } from './workflow-analytics.js';
31
32
 
@@ -719,6 +720,9 @@ export {
719
720
  export interface AsyncConversationExecutionPayload extends AsyncExecutionPayloadBase {
720
721
  type: 'conversation';
721
722
 
723
+ /** Effective tool approval mode for interactive agent conversations. */
724
+ tool_approval_mode?: AgentToolApprovalMode;
725
+
722
726
  /**
723
727
  * Visibility determine if the conversation should be seen by the user only or by anyone with access to the project
724
728
  * If not specified, the default is project
@@ -764,6 +768,14 @@ export interface AsyncConversationExecutionPayload extends AsyncExecutionPayload
764
768
  */
765
769
  collection_id?: string;
766
770
 
771
+ /**
772
+ * Denylist of MCP tool-collection ids deactivated for this conversation.
773
+ * `undefined`/empty means all installed/connected MCP collections are active (back-compat,
774
+ * and new servers stay active by default). Listed collections are excluded even if connected.
775
+ * Can be updated mid-conversation via the MCP config signal.
776
+ */
777
+ disabled_mcp_collections?: string[];
778
+
767
779
  /**
768
780
  * The token threshold in thousands (K) for creating checkpoints.
769
781
  * If total tokens exceed this value, a checkpoint will be created.
@@ -954,12 +966,6 @@ interface ResumeConversationPayload {
954
966
 
955
967
  export interface ToolResultContent {
956
968
  content: string;
957
- /**
958
- * Reference to text content stored outside Temporal/API payloads. Servers that
959
- * execute the next model turn should resolve this before constructing the
960
- * provider prompt.
961
- */
962
- content_ref?: TextArtifactReference;
963
969
  is_error: boolean;
964
970
  files?: string[];
965
971
  /**
@@ -2,6 +2,7 @@ export type {
2
2
  JSONSchema,
3
3
  JSONSchemaArray,
4
4
  JSONSchemaObject,
5
+ JSONSchemaProperties,
5
6
  JSONSchemaType,
6
7
  JSONSchemaTypeName,
7
8
  } from '@llumiverse/common';
@@ -3,10 +3,13 @@ import { Permission } from './access-control.js';
3
3
  export const OAUTH_SCOPE_OPENID = 'openid';
4
4
  export const OAUTH_SCOPE_PROFILE = 'profile';
5
5
  export const OAUTH_SCOPE_OFFLINE_ACCESS = 'offline_access';
6
+ export const OAUTH_SCOPE_PROJECT_SWITCH = 'project_switch';
6
7
 
7
8
  export const OAUTH_STANDARD_SCOPES = [OAUTH_SCOPE_OPENID, OAUTH_SCOPE_PROFILE, OAUTH_SCOPE_OFFLINE_ACCESS] as const;
9
+ export const OAUTH_PLATFORM_SCOPES = [OAUTH_SCOPE_PROJECT_SWITCH] as const;
8
10
 
9
11
  export type OAuthStandardScope = (typeof OAUTH_STANDARD_SCOPES)[number];
12
+ export type OAuthPlatformScope = (typeof OAUTH_PLATFORM_SCOPES)[number];
10
13
 
11
14
  const NON_OAUTH_PERMISSION_SCOPES = new Set<Permission>([
12
15
  Permission.api_key_secret_read,
@@ -17,6 +20,7 @@ const NON_OAUTH_PERMISSION_SCOPES = new Set<Permission>([
17
20
  ]);
18
21
  const OAUTH_PERMISSION_SCOPES = Object.values(Permission).filter((scope) => !NON_OAUTH_PERMISSION_SCOPES.has(scope));
19
22
  const OAUTH_STANDARD_SCOPE_SET = new Set<string>(OAUTH_STANDARD_SCOPES);
23
+ const OAUTH_PLATFORM_SCOPE_SET = new Set<string>(OAUTH_PLATFORM_SCOPES);
20
24
  const OAUTH_PERMISSION_SCOPE_SET = new Set<string>(OAUTH_PERMISSION_SCOPES);
21
25
  const OBJECT_ID_PATTERN = /^[0-9a-f]{24}$/i;
22
26
  const OAUTH_PROJECT_BINDING_SCOPE_PREFIX = 'project:';
@@ -29,12 +33,16 @@ export function isOAuthStandardScope(scope: string): scope is OAuthStandardScope
29
33
  return OAUTH_STANDARD_SCOPE_SET.has(scope);
30
34
  }
31
35
 
36
+ export function isOAuthPlatformScope(scope: string): scope is OAuthPlatformScope {
37
+ return OAUTH_PLATFORM_SCOPE_SET.has(scope);
38
+ }
39
+
32
40
  export function isOAuthPermissionScope(scope: string): scope is Permission {
33
41
  return OAUTH_PERMISSION_SCOPE_SET.has(scope);
34
42
  }
35
43
 
36
44
  export function isOAuthSupportedScope(scope: string): boolean {
37
- return isOAuthStandardScope(scope) || isOAuthPermissionScope(scope);
45
+ return isOAuthStandardScope(scope) || isOAuthPlatformScope(scope) || isOAuthPermissionScope(scope);
38
46
  }
39
47
 
40
48
  export function isOAuthProjectBindingScope(scope: string): boolean {
@@ -60,6 +68,10 @@ export function hasOAuthOfflineAccessScope(scopes: readonly string[]): boolean {
60
68
  return scopes.includes(OAUTH_SCOPE_OFFLINE_ACCESS);
61
69
  }
62
70
 
71
+ export function hasOAuthProjectSwitchScope(scopes: readonly string[]): boolean {
72
+ return scopes.includes(OAUTH_SCOPE_PROJECT_SWITCH);
73
+ }
74
+
63
75
  export function getOAuthScopesWithProfileDependency(scopes: readonly string[]): string[] {
64
76
  if (!hasOAuthOpenIdScope(scopes)) {
65
77
  return scopes.filter((scope) => scope !== OAUTH_SCOPE_PROFILE);
@@ -40,6 +40,13 @@ export interface OAuthClientData {
40
40
  status: OAuthClientStatus;
41
41
  project_binding_mode: OAuthProjectBindingMode;
42
42
  fixed_project_id?: string;
43
+ /**
44
+ * When true (the default for new clients), the client may only be authorized for projects in its
45
+ * owning account/organization. Set to false to allow authorization for any project the approving
46
+ * user can access, regardless of account — required for OAuth/MCP clients used across
47
+ * organizations. The owning account itself is internal and not exposed here.
48
+ */
49
+ restrict_to_owner_account?: boolean;
43
50
  metadata?: Record<string, unknown>;
44
51
  created_by?: string;
45
52
  client_secret_configured?: boolean;
@@ -119,6 +126,7 @@ export interface CreateOAuthClientPayload {
119
126
  default_scopes?: string[];
120
127
  project_binding_mode?: OAuthProjectBindingMode;
121
128
  fixed_project_id?: string;
129
+ restrict_to_owner_account?: boolean;
122
130
  client_secret?: string;
123
131
  metadata?: Record<string, unknown>;
124
132
  }
@@ -134,6 +142,7 @@ export interface UpdateOAuthClientPayload {
134
142
  status?: OAuthClientStatus;
135
143
  project_binding_mode?: OAuthProjectBindingMode;
136
144
  fixed_project_id?: string;
145
+ restrict_to_owner_account?: boolean;
137
146
  client_secret?: string;
138
147
  metadata?: Record<string, unknown>;
139
148
  }
@@ -203,6 +212,14 @@ export interface OAuthAuthorizationRequest {
203
212
  requested_project_id?: string;
204
213
  project_binding_mode: OAuthProjectBindingMode;
205
214
  fixed_project_id?: string;
215
+ /**
216
+ * When true, the consent UI must constrain project selection to {@link owner_account_id}: the
217
+ * client may only be authorized for projects in its owning account. False (default) lets the user
218
+ * authorize any project they can access. Mirrors the server-side authorization enforcement.
219
+ */
220
+ restrict_to_owner_account?: boolean;
221
+ /** The owning account the client is restricted to, when {@link restrict_to_owner_account} is true. */
222
+ owner_account_id?: string;
206
223
  status: OAuthAuthorizationRequestStatus;
207
224
  created_at: string;
208
225
  expires_at: string;
package/src/project.ts CHANGED
@@ -9,7 +9,7 @@ export interface ICreateProjectPayload {
9
9
  description?: string;
10
10
  auto_config?: boolean;
11
11
  }
12
- export enum ProjectRoles {
12
+ export enum SystemRoles {
13
13
  owner = 'owner', // all permissions
14
14
  admin = 'admin', // all permissions
15
15
  manager = 'manager', // all permissions but manage_account, manage_billing
@@ -30,14 +30,14 @@ export enum ProjectRoles {
30
30
 
31
31
  export function isRoleIncludedIn(role: string, includingRole: string) {
32
32
  switch (includingRole) {
33
- case ProjectRoles.owner:
33
+ case SystemRoles.owner:
34
34
  return true; // includes billing to?
35
- case ProjectRoles.admin:
36
- return role !== ProjectRoles.billing && role !== ProjectRoles.owner;
37
- case ProjectRoles.developer:
38
- return role === ProjectRoles.developer;
39
- case ProjectRoles.billing:
40
- return role === ProjectRoles.billing;
35
+ case SystemRoles.admin:
36
+ return role !== SystemRoles.billing && role !== SystemRoles.owner;
37
+ case SystemRoles.developer:
38
+ return role === SystemRoles.developer;
39
+ case SystemRoles.billing:
40
+ return role === SystemRoles.billing;
41
41
  default:
42
42
  return false;
43
43
  }
@@ -0,0 +1,58 @@
1
+ import type { Permission } from '../access-control.js';
2
+
3
+ /**
4
+ * Pure types & constants for the role system. This file is intentionally
5
+ * `class`-free — it is what stays in `@vertesia/common` when the class
6
+ * hierarchy (`classes.ts`) eventually moves to `studio-utils`. Client SDKs
7
+ * depend ONLY on these types, never on the registry runtime.
8
+ */
9
+
10
+ /**
11
+ * Kind of object a ContentSet's `resource_props` matches at query time. Used
12
+ * in `AceConditions.scope` (validated at runtime against this list) and as
13
+ * the prefix in JWT `content_security` keys (e.g. `collection:read`).
14
+ *
15
+ * Each scope is owned by exactly one partition. When adding a new partition
16
+ * (e.g. tasks), extend this list with the new scope(s) AND extend `RoleDomain`
17
+ * with the new domain.
18
+ */
19
+ export const AbacScopes = ['document', 'collection', 'task'] as const;
20
+ export type AbacScope = (typeof AbacScopes)[number];
21
+
22
+ /**
23
+ * Logical grouping of roles by the service area that owns them. One domain may
24
+ * declare roles applicable to multiple scopes (e.g. the `content` domain owns
25
+ * roles applicable to both `document` and `collection` scopes). The `system`
26
+ * domain owns the built-in foundational roles (currently exposed as
27
+ * `SystemRoles`) — registered first so domain partitions cannot shadow them.
28
+ */
29
+ export type RoleDomain = 'system' | 'content' | 'tasks';
30
+
31
+ /**
32
+ * Wire shape of a role returned by the IAM `/roles` endpoint.
33
+ *
34
+ * Permissions are typed `string[]` because role names span multiple partitions
35
+ * (system, content, future tasks/etc.) and each partition has its own
36
+ * vocabulary. For the tightly-typed system-only view (with `permissions:
37
+ * Permission[]`) use `SystemRoleDefinition` and the `/roles/system` endpoint.
38
+ *
39
+ * NOTE: this interface is intentionally non-generic. The OpenAPI generator
40
+ * doesn't handle TypeScript generics cleanly in array response types and
41
+ * produces a degenerate `RoleDefinitionArray` schema. Keeping the wire shapes
42
+ * concrete avoids that. `SystemRoleDefinition` extends and narrows
43
+ * `permissions` to `Permission[]`.
44
+ */
45
+ export interface RoleDefinition {
46
+ name: string;
47
+ permissions: string[];
48
+ domain: RoleDomain;
49
+ }
50
+
51
+ /**
52
+ * Tightly-typed view of a system-domain role: permissions are central
53
+ * `Permission` enum values. Returned by `client.iam.roles.listSystem()` and
54
+ * by the server's `/roles/system` endpoint.
55
+ */
56
+ export interface SystemRoleDefinition extends RoleDefinition {
57
+ permissions: Permission[];
58
+ }
@@ -0,0 +1,18 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { normalizeAgentToolApprovalMode } from './agent-approval.js';
3
+
4
+ describe('normalizeAgentToolApprovalMode', () => {
5
+ it('defaults interactive runs to full_control when no mode is supplied', () => {
6
+ expect(normalizeAgentToolApprovalMode(undefined, true)).toBe('full_control');
7
+ });
8
+
9
+ it('keeps supplied modes for interactive runs', () => {
10
+ expect(normalizeAgentToolApprovalMode('ask', true)).toBe('ask');
11
+ expect(normalizeAgentToolApprovalMode('auto_review', true)).toBe('auto_review');
12
+ });
13
+
14
+ it('forces non-interactive runs to full_control', () => {
15
+ expect(normalizeAgentToolApprovalMode('ask', false)).toBe('full_control');
16
+ expect(normalizeAgentToolApprovalMode('auto_review', undefined)).toBe('full_control');
17
+ });
18
+ });
@@ -0,0 +1,33 @@
1
+ import type { ToolResult } from '../interaction.js';
2
+
3
+ export const AgentToolApprovalModes = ['ask', 'auto_review', 'full_control'] as const;
4
+
5
+ export type AgentToolApprovalMode = (typeof AgentToolApprovalModes)[number];
6
+
7
+ export interface ToolApprovalGrant {
8
+ key: string;
9
+ tool_name: string;
10
+ target?: string;
11
+ granted_at: string;
12
+ }
13
+
14
+ export interface PendingToolApprovalResults {
15
+ results: ToolResult[];
16
+ reason: 'denied' | 'denied_with_feedback' | 'timeout' | 'reviewer_denied';
17
+ message: string;
18
+ created_at: string;
19
+ }
20
+
21
+ export function normalizeAgentToolApprovalMode(
22
+ mode: AgentToolApprovalMode | undefined,
23
+ interactive: boolean | undefined,
24
+ ): AgentToolApprovalMode {
25
+ if (interactive !== true) {
26
+ return 'full_control';
27
+ }
28
+ return mode ?? 'full_control';
29
+ }
30
+
31
+ export function isAgentToolApprovalMode(value: unknown): value is AgentToolApprovalMode {
32
+ return typeof value === 'string' && (AgentToolApprovalModes as readonly string[]).includes(value);
33
+ }
@@ -21,8 +21,9 @@ import type {
21
21
  RunSource,
22
22
  } from '../interaction.js';
23
23
  import type { AgentEvent } from '../workflow-analytics.js';
24
+ import type { AgentToolApprovalMode } from './agent-approval.js';
24
25
  import type { ProcessDefinitionBody, ProcessState } from './process.js';
25
- import type { UserInputSignal } from './signals.js';
26
+ import type { StopSignal, UserInputSignal } from './signals.js';
26
27
  import type { ContentObjectTypeRef } from './store.js';
27
28
  import type {
28
29
  AgentMessage,
@@ -158,12 +159,22 @@ export interface AgentRunBase<TData = Record<string, unknown>, TProperties = Rec
158
159
  /** Whether the agent accepts user input */
159
160
  interactive?: boolean;
160
161
 
162
+ /** How side-effecting tool actions are approved for interactive runs. */
163
+ tool_approval_mode?: AgentToolApprovalMode;
164
+
161
165
  /** Tools configured for this run (+/- syntax supported) */
162
166
  tool_names?: string[];
163
167
 
164
168
  /** Scoped collection (if any) */
165
169
  collection_id?: string;
166
170
 
171
+ /**
172
+ * Denylist of MCP tool-collection ids deactivated for this run.
173
+ * `undefined`/empty means all installed/connected MCP collections are active (back-compat,
174
+ * and new servers stay active by default). Listed collections are excluded even if connected.
175
+ */
176
+ disabled_mcp_collections?: string[];
177
+
167
178
  /** Content type linked to this run — defines the schema for `properties` */
168
179
  content_type?: ContentObjectTypeRef;
169
180
 
@@ -427,10 +438,15 @@ export interface UpdateAgentRunStatusPayload {
427
438
  title?: string;
428
439
  topic?: string;
429
440
  lessons_learned?: string[];
430
- /** Shallow-merged into the run's existing properties. */
431
- properties?: Record<string, unknown>;
432
441
  /** ES-only: conversation content text (not stored in MongoDB) */
433
442
  content?: string;
443
+ /**
444
+ * MCP collections deactivated for this run. Persisted when the user toggles activation
445
+ * mid-conversation so a page reload reflects the live state. An empty array clears the denylist.
446
+ */
447
+ disabled_mcp_collections?: string[];
448
+ /** Tool approval mode persisted for interactive agent runs. */
449
+ tool_approval_mode?: AgentToolApprovalMode;
434
450
  /** Archive state fields (set by the archive workflow) */
435
451
  archive_state?: AgentRunArchiveState;
436
452
  archived_at?: string;
@@ -445,6 +461,7 @@ export interface UpdateAgentRunStatusPayload {
445
461
  */
446
462
  export type SignalAgentPayload =
447
463
  | UserInputSignal
464
+ | StopSignal
448
465
  | ConversationFileRef
449
466
  | ConversationFileRemovedRef
450
467
  | Record<string, unknown>;