@meshagent/meshagent 0.49.1 → 0.51.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.
package/CHANGELOG.md CHANGED
@@ -1,7 +1,21 @@
1
+ ## [0.51.0]
2
+ - Refactored the chat UI to split input from feed, simplifying thread and dataset views and removing suggestion-driven behavior.
3
+ - Updated the JavaScript entrypoint and related tests to match the slimmer chat experience.
4
+
5
+ ## [0.50.1]
6
+ - Stability
7
+
8
+ ## [0.50.0]
9
+ - Chat clients now support per-turn LLM authorization providers, and websocket chat tokens are optional for `auth=none` deployments.
10
+ - The typed client gained `connectLlm`, optional access-subject IDs, service-account principals, room and service enabled flags, `llm_quota_manager`, and the `router` project settings document.
11
+ - Chat-thread constructors now take a chat client instead of requiring a room client, which is a breaking signature change for callers.
12
+ - The Tailwind chat package was updated to `tailwindcss` 4.3.3, and the chat and thread UI was refactored for more reliable optimistic streaming plus richer attachment and thread handling.
13
+
1
14
  ## [0.49.1]
2
15
  - Stability
3
16
 
4
17
  ## [0.49.0]
18
+ - Added typed service enable/disable state with backward-compatible enabled defaults.
5
19
  - Breaking: `createProject` no longer accepts inline settings; project settings are now document-based with `room_roles` support.
6
20
  - Route path models now use a service-port/content-target union and support CORS, compression, index, and IAP for room-content routes.
7
21
  - `RoomRole` now includes `guest`, and missing project-settings documents return `undefined`.
@@ -1,8 +1,8 @@
1
1
  import { ApiScope } from "./participant-token.js";
2
- export type ProjectRole = "member" | "admin" | "developer" | "room_creator" | "room_inventory" | "room_manager" | "session_inventory" | "agent_creator" | "agent_inventory" | "agent_manager" | "repository_creator" | "repository_inventory" | "repository_manager" | "feed_creator" | "feed_inventory" | "feed_manager" | "oauth_client_creator" | "oauth_client_inventory" | "oauth_client_manager" | "api_key_creator" | "api_key_inventory" | "api_key_manager" | "service_creator" | "service_inventory" | "service_manager" | "service_account_creator" | "service_account_inventory" | "service_account_manager" | "participant_token_creator" | "mailbox_creator" | "mailbox_inventory" | "mailbox_manager" | "route_creator" | "route_inventory" | "route_manager" | "scheduled_task_creator" | "scheduled_task_inventory" | "scheduled_task_manager" | "feed_subscription_creator" | "feed_subscription_inventory" | "feed_subscription_manager" | "llm_logger_creator" | "llm_logger_inventory" | "llm_logger_manager" | "llm_proxy_user" | "usage_reporter" | "billing_manager" | "group_manager";
2
+ export type ProjectRole = "member" | "admin" | "developer" | "room_creator" | "room_inventory" | "room_manager" | "session_inventory" | "agent_creator" | "agent_inventory" | "agent_manager" | "repository_creator" | "repository_inventory" | "repository_manager" | "feed_creator" | "feed_inventory" | "feed_manager" | "oauth_client_creator" | "oauth_client_inventory" | "oauth_client_manager" | "api_key_creator" | "api_key_inventory" | "api_key_manager" | "service_creator" | "service_inventory" | "service_manager" | "service_account_creator" | "service_account_inventory" | "service_account_manager" | "participant_token_creator" | "mailbox_creator" | "mailbox_inventory" | "mailbox_manager" | "route_creator" | "route_inventory" | "route_manager" | "scheduled_task_creator" | "scheduled_task_inventory" | "scheduled_task_manager" | "feed_subscription_creator" | "feed_subscription_inventory" | "feed_subscription_manager" | "llm_logger_creator" | "llm_logger_inventory" | "llm_logger_manager" | "llm_proxy_user" | "llm_quota_manager" | "usage_reporter" | "billing_manager" | "group_manager";
3
3
  export type ResourceRole = "viewer" | "operator" | "developer" | "admin";
4
4
  export type RoomRole = "site_user" | "guest" | ResourceRole;
5
- export type ProjectSettingsDocumentName = "openai" | "anthropic" | "otel" | "admission" | "room" | "room_roles";
5
+ export type ProjectSettingsDocumentName = "openai" | "anthropic" | "otel" | "admission" | "room" | "room_roles" | "router";
6
6
  export type FeedRole = "reader" | "subscriber" | "publisher" | "manager";
7
7
  export type SecretRole = "use_proxy";
8
8
  export type AccessRole = ProjectRole | RoomRole | FeedRole | SecretRole | "list";
@@ -10,13 +10,25 @@ export type AccessSubjectType = "user" | "group" | "agent" | "service_account" |
10
10
  export type AccessResourceType = "project" | "room" | "agent" | "group" | "repository" | "feed" | "secret";
11
11
  export interface AccessSubject {
12
12
  type: AccessSubjectType;
13
- id: string;
13
+ id?: string | null;
14
14
  name?: string | null;
15
15
  firstName?: string | null;
16
16
  lastName?: string | null;
17
17
  email?: string | null;
18
18
  objectType?: "project" | null;
19
- relation?: "member" | "developer" | "agent" | null;
19
+ relation?: "member" | "developer" | "agent" | "service_account" | null;
20
+ }
21
+ export type LlmProvider = "openai" | "anthropic";
22
+ export interface LlmDelegation {
23
+ id: string;
24
+ token: string;
25
+ expiresAt: string;
26
+ projectId: string;
27
+ delegator: AccessSubject;
28
+ subject: AccessSubject;
29
+ providers?: LlmProvider[] | null;
30
+ models?: string[] | null;
31
+ maxBudget: string;
20
32
  }
21
33
  export interface AccessResource {
22
34
  type: AccessResourceType;
@@ -66,6 +78,21 @@ export interface RoomInfo {
66
78
  metadata: Record<string, unknown>;
67
79
  annotations: Record<string, string>;
68
80
  }
81
+ export type RoomAllocationStatus = "Allocated" | "Unallocated";
82
+ export interface RoomStatus {
83
+ status: RoomAllocationStatus;
84
+ allocatedAt?: Date | null;
85
+ runningForSeconds?: number | null;
86
+ }
87
+ export interface RoomLifecycleEvent {
88
+ id: string;
89
+ roomName: string;
90
+ sessionId?: string | null;
91
+ type: string;
92
+ message: string;
93
+ severity?: string | null;
94
+ createdAt: Date;
95
+ }
69
96
  export interface GroupInfo {
70
97
  id: string;
71
98
  name: string;
@@ -401,6 +428,7 @@ export interface ServiceSpec {
401
428
  version: "v1";
402
429
  kind: "Service";
403
430
  id?: string | null;
431
+ enabled?: boolean;
404
432
  metadata: ServiceMetadata;
405
433
  agents?: AgentSpec[] | null;
406
434
  ports?: PortSpec[];
@@ -578,6 +606,8 @@ export declare class Meshagent {
578
606
  private secretVersionPayload;
579
607
  private parseRoomSession;
580
608
  private parseRoom;
609
+ private parseRoomStatus;
610
+ private parseRoomLifecycleEvent;
581
611
  private parseGroup;
582
612
  private parseRoute;
583
613
  private parseFeed;
@@ -587,6 +617,7 @@ export declare class Meshagent {
587
617
  private parseAccessResource;
588
618
  private parseAccessSubject;
589
619
  private serializeAccessSubject;
620
+ private parseLlmDelegation;
590
621
  private serializeAccessResource;
591
622
  private parseProjectMember;
592
623
  private parseGroupMember;
@@ -900,6 +931,10 @@ export declare class Meshagent {
900
931
  annotations?: Record<string, string>;
901
932
  }): Promise<RoomInfo>;
902
933
  getRoom(projectId: string, name: string): Promise<RoomInfo>;
934
+ getRoomStatus(projectId: string, name: string): Promise<RoomStatus>;
935
+ listRoomEvents(projectId: string, name: string, options?: {
936
+ limit?: number;
937
+ }): Promise<RoomLifecycleEvent[]>;
903
938
  updateRoom(projectId: string, roomId: string, name: string, options?: {
904
939
  metadata?: Record<string, unknown>;
905
940
  annotations?: Record<string, string>;
@@ -949,6 +984,14 @@ export declare class Meshagent {
949
984
  }): Promise<void>;
950
985
  connectRoom(projectId: string, room: string): Promise<RoomConnectionInfo>;
951
986
  connectAgent(projectId: string, agentName: string): Promise<AgentConnectionInfo>;
987
+ connectLlm(params: {
988
+ projectId: string;
989
+ subject: AccessSubject;
990
+ maxBudget: string;
991
+ providers?: LlmProvider[];
992
+ models?: string[];
993
+ expiresInSeconds?: number;
994
+ }): Promise<LlmDelegation>;
952
995
  listRooms(projectId: string, options?: {
953
996
  pageSize?: number;
954
997
  continuationToken?: string;
@@ -83,7 +83,7 @@ function normalizeServiceSpec(service) {
83
83
  })),
84
84
  },
85
85
  };
86
- return { ...service, agents, container };
86
+ return { ...service, enabled: service.enabled ?? true, agents, container };
87
87
  }
88
88
  class ServiceTemplateSpec {
89
89
  constructor(template) {
@@ -199,6 +199,7 @@ function serializeServiceSpec(service) {
199
199
  };
200
200
  return pruneUndefinedValues({
201
201
  ...service,
202
+ enabled: service.enabled ?? true,
202
203
  container,
203
204
  agents,
204
205
  });
@@ -399,6 +400,54 @@ class Meshagent {
399
400
  annotations: annotations && typeof annotations === "object" ? annotations : {},
400
401
  };
401
402
  }
403
+ parseRoomStatus(data) {
404
+ if (!data || typeof data !== "object") {
405
+ throw new requirement_js_1.RoomException("Invalid room status payload");
406
+ }
407
+ const { status, allocated_at: allocatedAt, running_for_seconds: runningForSeconds, } = data;
408
+ if (status !== "Allocated" && status !== "Unallocated") {
409
+ throw new requirement_js_1.RoomException("Invalid room status payload: unknown status");
410
+ }
411
+ if (allocatedAt != null && typeof allocatedAt !== "string") {
412
+ throw new requirement_js_1.RoomException("Invalid room status payload: allocated_at must be a timestamp");
413
+ }
414
+ if (runningForSeconds != null && typeof runningForSeconds !== "number") {
415
+ throw new requirement_js_1.RoomException("Invalid room status payload: running_for_seconds must be a number");
416
+ }
417
+ return {
418
+ status,
419
+ allocatedAt: allocatedAt == null ? null : new Date(allocatedAt),
420
+ runningForSeconds: runningForSeconds == null ? null : runningForSeconds,
421
+ };
422
+ }
423
+ parseRoomLifecycleEvent(data) {
424
+ if (!data || typeof data !== "object") {
425
+ throw new requirement_js_1.RoomException("Invalid room lifecycle event payload");
426
+ }
427
+ const { id, room_name: roomName, session_id: sessionId, type, message, severity, created_at: createdAt, } = data;
428
+ if (typeof id !== "string"
429
+ || typeof roomName !== "string"
430
+ || typeof type !== "string"
431
+ || typeof message !== "string"
432
+ || typeof createdAt !== "string") {
433
+ throw new requirement_js_1.RoomException("Invalid room lifecycle event payload: missing required fields");
434
+ }
435
+ if (sessionId != null && typeof sessionId !== "string") {
436
+ throw new requirement_js_1.RoomException("Invalid room lifecycle event payload: session_id must be a string");
437
+ }
438
+ if (severity != null && typeof severity !== "string") {
439
+ throw new requirement_js_1.RoomException("Invalid room lifecycle event payload: severity must be a string");
440
+ }
441
+ return {
442
+ id,
443
+ roomName,
444
+ sessionId: sessionId == null ? null : sessionId,
445
+ type,
446
+ message,
447
+ severity: severity == null ? null : severity,
448
+ createdAt: new Date(createdAt),
449
+ };
450
+ }
402
451
  parseGroup(data) {
403
452
  if (!data || typeof data !== "object") {
404
453
  throw new requirement_js_1.RoomException("Invalid group payload");
@@ -595,7 +644,7 @@ class Meshagent {
595
644
  serializeAccessSubject(subject) {
596
645
  return {
597
646
  type: subject.type,
598
- id: subject.id,
647
+ ...(subject.id !== undefined ? { id: subject.id } : {}),
599
648
  ...(subject.name !== undefined ? { name: subject.name } : {}),
600
649
  ...(subject.firstName !== undefined ? { first_name: subject.firstName } : {}),
601
650
  ...(subject.lastName !== undefined ? { last_name: subject.lastName } : {}),
@@ -604,6 +653,24 @@ class Meshagent {
604
653
  ...(subject.relation !== undefined ? { relation: subject.relation } : {}),
605
654
  };
606
655
  }
656
+ parseLlmDelegation(data) {
657
+ if (!data || typeof data !== "object" || typeof data.id !== "string" || typeof data.token !== "string"
658
+ || typeof data.expires_at !== "string" || typeof data.project_id !== "string"
659
+ || typeof data.max_budget !== "string") {
660
+ throw new requirement_js_1.RoomException("Invalid LLM delegation payload");
661
+ }
662
+ return {
663
+ id: data.id,
664
+ token: data.token,
665
+ expiresAt: data.expires_at,
666
+ projectId: data.project_id,
667
+ delegator: this.parseAccessSubject(data.delegator),
668
+ subject: this.parseAccessSubject(data.subject),
669
+ providers: Array.isArray(data.providers) ? data.providers : null,
670
+ models: Array.isArray(data.models) ? data.models.filter((value) => typeof value === "string") : null,
671
+ maxBudget: data.max_budget,
672
+ };
673
+ }
607
674
  serializeAccessResource(resource) {
608
675
  return {
609
676
  type: resource.type,
@@ -724,6 +791,9 @@ class Meshagent {
724
791
  metadata: parsedResource.metadata ?? {},
725
792
  annotations: parsedResource.annotations ?? {},
726
793
  };
794
+ if (!parsedSubject.id) {
795
+ throw new requirement_js_1.RoomException("Invalid room grant payload: missing subject id");
796
+ }
727
797
  return {
728
798
  resource: parsedResource,
729
799
  subject: parsedSubject,
@@ -1770,6 +1840,22 @@ class Meshagent {
1770
1840
  });
1771
1841
  return this.parseRoom(data);
1772
1842
  }
1843
+ async getRoomStatus(projectId, name) {
1844
+ const roomName = this.encodePathComponent(name);
1845
+ const data = await this.request(`/accounts/projects/${projectId}/rooms/${roomName}/status`, {
1846
+ action: "get room status",
1847
+ });
1848
+ return this.parseRoomStatus(data);
1849
+ }
1850
+ async listRoomEvents(projectId, name, options = {}) {
1851
+ const roomName = this.encodePathComponent(name);
1852
+ const data = await this.request(`/accounts/projects/${projectId}/rooms/${roomName}/events`, {
1853
+ query: { limit: options.limit ?? 100 },
1854
+ action: "list room lifecycle events",
1855
+ });
1856
+ const events = Array.isArray(data?.events) ? data.events : [];
1857
+ return events.map((event) => this.parseRoomLifecycleEvent(event));
1858
+ }
1773
1859
  async updateRoom(projectId, roomId, name, options = {}) {
1774
1860
  const payload = { name };
1775
1861
  if (options.metadata !== undefined) {
@@ -1893,6 +1979,21 @@ class Meshagent {
1893
1979
  });
1894
1980
  return this.parseAgentConnectionInfo(data);
1895
1981
  }
1982
+ async connectLlm(params) {
1983
+ const data = await this.request("/llm/connect", {
1984
+ method: "POST",
1985
+ headers: { "Meshagent-Project-Id": params.projectId },
1986
+ json: {
1987
+ subject: this.serializeAccessSubject(params.subject),
1988
+ max_budget: params.maxBudget,
1989
+ ...(params.providers !== undefined ? { providers: params.providers } : {}),
1990
+ ...(params.models !== undefined ? { models: params.models } : {}),
1991
+ ...(params.expiresInSeconds !== undefined ? { expires_in_seconds: params.expiresInSeconds } : {}),
1992
+ },
1993
+ action: "connect LLM delegation",
1994
+ });
1995
+ return this.parseLlmDelegation(data);
1996
+ }
1896
1997
  async listRooms(projectId, options = {}) {
1897
1998
  const { pageSize = 50, continuationToken, filter, view } = options;
1898
1999
  const data = await this.request(`/accounts/projects/${projectId}/rooms`, {
@@ -1,8 +1,8 @@
1
1
  import { ApiScope } from "./participant-token.js";
2
- export type ProjectRole = "member" | "admin" | "developer" | "room_creator" | "room_inventory" | "room_manager" | "session_inventory" | "agent_creator" | "agent_inventory" | "agent_manager" | "repository_creator" | "repository_inventory" | "repository_manager" | "feed_creator" | "feed_inventory" | "feed_manager" | "oauth_client_creator" | "oauth_client_inventory" | "oauth_client_manager" | "api_key_creator" | "api_key_inventory" | "api_key_manager" | "service_creator" | "service_inventory" | "service_manager" | "service_account_creator" | "service_account_inventory" | "service_account_manager" | "participant_token_creator" | "mailbox_creator" | "mailbox_inventory" | "mailbox_manager" | "route_creator" | "route_inventory" | "route_manager" | "scheduled_task_creator" | "scheduled_task_inventory" | "scheduled_task_manager" | "feed_subscription_creator" | "feed_subscription_inventory" | "feed_subscription_manager" | "llm_logger_creator" | "llm_logger_inventory" | "llm_logger_manager" | "llm_proxy_user" | "usage_reporter" | "billing_manager" | "group_manager";
2
+ export type ProjectRole = "member" | "admin" | "developer" | "room_creator" | "room_inventory" | "room_manager" | "session_inventory" | "agent_creator" | "agent_inventory" | "agent_manager" | "repository_creator" | "repository_inventory" | "repository_manager" | "feed_creator" | "feed_inventory" | "feed_manager" | "oauth_client_creator" | "oauth_client_inventory" | "oauth_client_manager" | "api_key_creator" | "api_key_inventory" | "api_key_manager" | "service_creator" | "service_inventory" | "service_manager" | "service_account_creator" | "service_account_inventory" | "service_account_manager" | "participant_token_creator" | "mailbox_creator" | "mailbox_inventory" | "mailbox_manager" | "route_creator" | "route_inventory" | "route_manager" | "scheduled_task_creator" | "scheduled_task_inventory" | "scheduled_task_manager" | "feed_subscription_creator" | "feed_subscription_inventory" | "feed_subscription_manager" | "llm_logger_creator" | "llm_logger_inventory" | "llm_logger_manager" | "llm_proxy_user" | "llm_quota_manager" | "usage_reporter" | "billing_manager" | "group_manager";
3
3
  export type ResourceRole = "viewer" | "operator" | "developer" | "admin";
4
4
  export type RoomRole = "site_user" | "guest" | ResourceRole;
5
- export type ProjectSettingsDocumentName = "openai" | "anthropic" | "otel" | "admission" | "room" | "room_roles";
5
+ export type ProjectSettingsDocumentName = "openai" | "anthropic" | "otel" | "admission" | "room" | "room_roles" | "router";
6
6
  export type FeedRole = "reader" | "subscriber" | "publisher" | "manager";
7
7
  export type SecretRole = "use_proxy";
8
8
  export type AccessRole = ProjectRole | RoomRole | FeedRole | SecretRole | "list";
@@ -10,13 +10,25 @@ export type AccessSubjectType = "user" | "group" | "agent" | "service_account" |
10
10
  export type AccessResourceType = "project" | "room" | "agent" | "group" | "repository" | "feed" | "secret";
11
11
  export interface AccessSubject {
12
12
  type: AccessSubjectType;
13
- id: string;
13
+ id?: string | null;
14
14
  name?: string | null;
15
15
  firstName?: string | null;
16
16
  lastName?: string | null;
17
17
  email?: string | null;
18
18
  objectType?: "project" | null;
19
- relation?: "member" | "developer" | "agent" | null;
19
+ relation?: "member" | "developer" | "agent" | "service_account" | null;
20
+ }
21
+ export type LlmProvider = "openai" | "anthropic";
22
+ export interface LlmDelegation {
23
+ id: string;
24
+ token: string;
25
+ expiresAt: string;
26
+ projectId: string;
27
+ delegator: AccessSubject;
28
+ subject: AccessSubject;
29
+ providers?: LlmProvider[] | null;
30
+ models?: string[] | null;
31
+ maxBudget: string;
20
32
  }
21
33
  export interface AccessResource {
22
34
  type: AccessResourceType;
@@ -66,6 +78,21 @@ export interface RoomInfo {
66
78
  metadata: Record<string, unknown>;
67
79
  annotations: Record<string, string>;
68
80
  }
81
+ export type RoomAllocationStatus = "Allocated" | "Unallocated";
82
+ export interface RoomStatus {
83
+ status: RoomAllocationStatus;
84
+ allocatedAt?: Date | null;
85
+ runningForSeconds?: number | null;
86
+ }
87
+ export interface RoomLifecycleEvent {
88
+ id: string;
89
+ roomName: string;
90
+ sessionId?: string | null;
91
+ type: string;
92
+ message: string;
93
+ severity?: string | null;
94
+ createdAt: Date;
95
+ }
69
96
  export interface GroupInfo {
70
97
  id: string;
71
98
  name: string;
@@ -401,6 +428,7 @@ export interface ServiceSpec {
401
428
  version: "v1";
402
429
  kind: "Service";
403
430
  id?: string | null;
431
+ enabled?: boolean;
404
432
  metadata: ServiceMetadata;
405
433
  agents?: AgentSpec[] | null;
406
434
  ports?: PortSpec[];
@@ -578,6 +606,8 @@ export declare class Meshagent {
578
606
  private secretVersionPayload;
579
607
  private parseRoomSession;
580
608
  private parseRoom;
609
+ private parseRoomStatus;
610
+ private parseRoomLifecycleEvent;
581
611
  private parseGroup;
582
612
  private parseRoute;
583
613
  private parseFeed;
@@ -587,6 +617,7 @@ export declare class Meshagent {
587
617
  private parseAccessResource;
588
618
  private parseAccessSubject;
589
619
  private serializeAccessSubject;
620
+ private parseLlmDelegation;
590
621
  private serializeAccessResource;
591
622
  private parseProjectMember;
592
623
  private parseGroupMember;
@@ -900,6 +931,10 @@ export declare class Meshagent {
900
931
  annotations?: Record<string, string>;
901
932
  }): Promise<RoomInfo>;
902
933
  getRoom(projectId: string, name: string): Promise<RoomInfo>;
934
+ getRoomStatus(projectId: string, name: string): Promise<RoomStatus>;
935
+ listRoomEvents(projectId: string, name: string, options?: {
936
+ limit?: number;
937
+ }): Promise<RoomLifecycleEvent[]>;
903
938
  updateRoom(projectId: string, roomId: string, name: string, options?: {
904
939
  metadata?: Record<string, unknown>;
905
940
  annotations?: Record<string, string>;
@@ -949,6 +984,14 @@ export declare class Meshagent {
949
984
  }): Promise<void>;
950
985
  connectRoom(projectId: string, room: string): Promise<RoomConnectionInfo>;
951
986
  connectAgent(projectId: string, agentName: string): Promise<AgentConnectionInfo>;
987
+ connectLlm(params: {
988
+ projectId: string;
989
+ subject: AccessSubject;
990
+ maxBudget: string;
991
+ providers?: LlmProvider[];
992
+ models?: string[];
993
+ expiresInSeconds?: number;
994
+ }): Promise<LlmDelegation>;
952
995
  listRooms(projectId: string, options?: {
953
996
  pageSize?: number;
954
997
  continuationToken?: string;
@@ -79,7 +79,7 @@ function normalizeServiceSpec(service) {
79
79
  })),
80
80
  },
81
81
  };
82
- return { ...service, agents, container };
82
+ return { ...service, enabled: service.enabled ?? true, agents, container };
83
83
  }
84
84
  export class ServiceTemplateSpec {
85
85
  constructor(template) {
@@ -194,6 +194,7 @@ function serializeServiceSpec(service) {
194
194
  };
195
195
  return pruneUndefinedValues({
196
196
  ...service,
197
+ enabled: service.enabled ?? true,
197
198
  container,
198
199
  agents,
199
200
  });
@@ -394,6 +395,54 @@ export class Meshagent {
394
395
  annotations: annotations && typeof annotations === "object" ? annotations : {},
395
396
  };
396
397
  }
398
+ parseRoomStatus(data) {
399
+ if (!data || typeof data !== "object") {
400
+ throw new RoomException("Invalid room status payload");
401
+ }
402
+ const { status, allocated_at: allocatedAt, running_for_seconds: runningForSeconds, } = data;
403
+ if (status !== "Allocated" && status !== "Unallocated") {
404
+ throw new RoomException("Invalid room status payload: unknown status");
405
+ }
406
+ if (allocatedAt != null && typeof allocatedAt !== "string") {
407
+ throw new RoomException("Invalid room status payload: allocated_at must be a timestamp");
408
+ }
409
+ if (runningForSeconds != null && typeof runningForSeconds !== "number") {
410
+ throw new RoomException("Invalid room status payload: running_for_seconds must be a number");
411
+ }
412
+ return {
413
+ status,
414
+ allocatedAt: allocatedAt == null ? null : new Date(allocatedAt),
415
+ runningForSeconds: runningForSeconds == null ? null : runningForSeconds,
416
+ };
417
+ }
418
+ parseRoomLifecycleEvent(data) {
419
+ if (!data || typeof data !== "object") {
420
+ throw new RoomException("Invalid room lifecycle event payload");
421
+ }
422
+ const { id, room_name: roomName, session_id: sessionId, type, message, severity, created_at: createdAt, } = data;
423
+ if (typeof id !== "string"
424
+ || typeof roomName !== "string"
425
+ || typeof type !== "string"
426
+ || typeof message !== "string"
427
+ || typeof createdAt !== "string") {
428
+ throw new RoomException("Invalid room lifecycle event payload: missing required fields");
429
+ }
430
+ if (sessionId != null && typeof sessionId !== "string") {
431
+ throw new RoomException("Invalid room lifecycle event payload: session_id must be a string");
432
+ }
433
+ if (severity != null && typeof severity !== "string") {
434
+ throw new RoomException("Invalid room lifecycle event payload: severity must be a string");
435
+ }
436
+ return {
437
+ id,
438
+ roomName,
439
+ sessionId: sessionId == null ? null : sessionId,
440
+ type,
441
+ message,
442
+ severity: severity == null ? null : severity,
443
+ createdAt: new Date(createdAt),
444
+ };
445
+ }
397
446
  parseGroup(data) {
398
447
  if (!data || typeof data !== "object") {
399
448
  throw new RoomException("Invalid group payload");
@@ -590,7 +639,7 @@ export class Meshagent {
590
639
  serializeAccessSubject(subject) {
591
640
  return {
592
641
  type: subject.type,
593
- id: subject.id,
642
+ ...(subject.id !== undefined ? { id: subject.id } : {}),
594
643
  ...(subject.name !== undefined ? { name: subject.name } : {}),
595
644
  ...(subject.firstName !== undefined ? { first_name: subject.firstName } : {}),
596
645
  ...(subject.lastName !== undefined ? { last_name: subject.lastName } : {}),
@@ -599,6 +648,24 @@ export class Meshagent {
599
648
  ...(subject.relation !== undefined ? { relation: subject.relation } : {}),
600
649
  };
601
650
  }
651
+ parseLlmDelegation(data) {
652
+ if (!data || typeof data !== "object" || typeof data.id !== "string" || typeof data.token !== "string"
653
+ || typeof data.expires_at !== "string" || typeof data.project_id !== "string"
654
+ || typeof data.max_budget !== "string") {
655
+ throw new RoomException("Invalid LLM delegation payload");
656
+ }
657
+ return {
658
+ id: data.id,
659
+ token: data.token,
660
+ expiresAt: data.expires_at,
661
+ projectId: data.project_id,
662
+ delegator: this.parseAccessSubject(data.delegator),
663
+ subject: this.parseAccessSubject(data.subject),
664
+ providers: Array.isArray(data.providers) ? data.providers : null,
665
+ models: Array.isArray(data.models) ? data.models.filter((value) => typeof value === "string") : null,
666
+ maxBudget: data.max_budget,
667
+ };
668
+ }
602
669
  serializeAccessResource(resource) {
603
670
  return {
604
671
  type: resource.type,
@@ -719,6 +786,9 @@ export class Meshagent {
719
786
  metadata: parsedResource.metadata ?? {},
720
787
  annotations: parsedResource.annotations ?? {},
721
788
  };
789
+ if (!parsedSubject.id) {
790
+ throw new RoomException("Invalid room grant payload: missing subject id");
791
+ }
722
792
  return {
723
793
  resource: parsedResource,
724
794
  subject: parsedSubject,
@@ -1765,6 +1835,22 @@ export class Meshagent {
1765
1835
  });
1766
1836
  return this.parseRoom(data);
1767
1837
  }
1838
+ async getRoomStatus(projectId, name) {
1839
+ const roomName = this.encodePathComponent(name);
1840
+ const data = await this.request(`/accounts/projects/${projectId}/rooms/${roomName}/status`, {
1841
+ action: "get room status",
1842
+ });
1843
+ return this.parseRoomStatus(data);
1844
+ }
1845
+ async listRoomEvents(projectId, name, options = {}) {
1846
+ const roomName = this.encodePathComponent(name);
1847
+ const data = await this.request(`/accounts/projects/${projectId}/rooms/${roomName}/events`, {
1848
+ query: { limit: options.limit ?? 100 },
1849
+ action: "list room lifecycle events",
1850
+ });
1851
+ const events = Array.isArray(data?.events) ? data.events : [];
1852
+ return events.map((event) => this.parseRoomLifecycleEvent(event));
1853
+ }
1768
1854
  async updateRoom(projectId, roomId, name, options = {}) {
1769
1855
  const payload = { name };
1770
1856
  if (options.metadata !== undefined) {
@@ -1888,6 +1974,21 @@ export class Meshagent {
1888
1974
  });
1889
1975
  return this.parseAgentConnectionInfo(data);
1890
1976
  }
1977
+ async connectLlm(params) {
1978
+ const data = await this.request("/llm/connect", {
1979
+ method: "POST",
1980
+ headers: { "Meshagent-Project-Id": params.projectId },
1981
+ json: {
1982
+ subject: this.serializeAccessSubject(params.subject),
1983
+ max_budget: params.maxBudget,
1984
+ ...(params.providers !== undefined ? { providers: params.providers } : {}),
1985
+ ...(params.models !== undefined ? { models: params.models } : {}),
1986
+ ...(params.expiresInSeconds !== undefined ? { expires_in_seconds: params.expiresInSeconds } : {}),
1987
+ },
1988
+ action: "connect LLM delegation",
1989
+ });
1990
+ return this.parseLlmDelegation(data);
1991
+ }
1891
1992
  async listRooms(projectId, options = {}) {
1892
1993
  const { pageSize = 50, continuationToken, filter, view } = options;
1893
1994
  const data = await this.request(`/accounts/projects/${projectId}/rooms`, {
@@ -1,8 +1,8 @@
1
1
  import { ApiScope } from "./participant-token.js";
2
- export type ProjectRole = "member" | "admin" | "developer" | "room_creator" | "room_inventory" | "room_manager" | "session_inventory" | "agent_creator" | "agent_inventory" | "agent_manager" | "repository_creator" | "repository_inventory" | "repository_manager" | "feed_creator" | "feed_inventory" | "feed_manager" | "oauth_client_creator" | "oauth_client_inventory" | "oauth_client_manager" | "api_key_creator" | "api_key_inventory" | "api_key_manager" | "service_creator" | "service_inventory" | "service_manager" | "service_account_creator" | "service_account_inventory" | "service_account_manager" | "participant_token_creator" | "mailbox_creator" | "mailbox_inventory" | "mailbox_manager" | "route_creator" | "route_inventory" | "route_manager" | "scheduled_task_creator" | "scheduled_task_inventory" | "scheduled_task_manager" | "feed_subscription_creator" | "feed_subscription_inventory" | "feed_subscription_manager" | "llm_logger_creator" | "llm_logger_inventory" | "llm_logger_manager" | "llm_proxy_user" | "usage_reporter" | "billing_manager" | "group_manager";
2
+ export type ProjectRole = "member" | "admin" | "developer" | "room_creator" | "room_inventory" | "room_manager" | "session_inventory" | "agent_creator" | "agent_inventory" | "agent_manager" | "repository_creator" | "repository_inventory" | "repository_manager" | "feed_creator" | "feed_inventory" | "feed_manager" | "oauth_client_creator" | "oauth_client_inventory" | "oauth_client_manager" | "api_key_creator" | "api_key_inventory" | "api_key_manager" | "service_creator" | "service_inventory" | "service_manager" | "service_account_creator" | "service_account_inventory" | "service_account_manager" | "participant_token_creator" | "mailbox_creator" | "mailbox_inventory" | "mailbox_manager" | "route_creator" | "route_inventory" | "route_manager" | "scheduled_task_creator" | "scheduled_task_inventory" | "scheduled_task_manager" | "feed_subscription_creator" | "feed_subscription_inventory" | "feed_subscription_manager" | "llm_logger_creator" | "llm_logger_inventory" | "llm_logger_manager" | "llm_proxy_user" | "llm_quota_manager" | "usage_reporter" | "billing_manager" | "group_manager";
3
3
  export type ResourceRole = "viewer" | "operator" | "developer" | "admin";
4
4
  export type RoomRole = "site_user" | "guest" | ResourceRole;
5
- export type ProjectSettingsDocumentName = "openai" | "anthropic" | "otel" | "admission" | "room" | "room_roles";
5
+ export type ProjectSettingsDocumentName = "openai" | "anthropic" | "otel" | "admission" | "room" | "room_roles" | "router";
6
6
  export type FeedRole = "reader" | "subscriber" | "publisher" | "manager";
7
7
  export type SecretRole = "use_proxy";
8
8
  export type AccessRole = ProjectRole | RoomRole | FeedRole | SecretRole | "list";
@@ -10,13 +10,25 @@ export type AccessSubjectType = "user" | "group" | "agent" | "service_account" |
10
10
  export type AccessResourceType = "project" | "room" | "agent" | "group" | "repository" | "feed" | "secret";
11
11
  export interface AccessSubject {
12
12
  type: AccessSubjectType;
13
- id: string;
13
+ id?: string | null;
14
14
  name?: string | null;
15
15
  firstName?: string | null;
16
16
  lastName?: string | null;
17
17
  email?: string | null;
18
18
  objectType?: "project" | null;
19
- relation?: "member" | "developer" | "agent" | null;
19
+ relation?: "member" | "developer" | "agent" | "service_account" | null;
20
+ }
21
+ export type LlmProvider = "openai" | "anthropic";
22
+ export interface LlmDelegation {
23
+ id: string;
24
+ token: string;
25
+ expiresAt: string;
26
+ projectId: string;
27
+ delegator: AccessSubject;
28
+ subject: AccessSubject;
29
+ providers?: LlmProvider[] | null;
30
+ models?: string[] | null;
31
+ maxBudget: string;
20
32
  }
21
33
  export interface AccessResource {
22
34
  type: AccessResourceType;
@@ -66,6 +78,21 @@ export interface RoomInfo {
66
78
  metadata: Record<string, unknown>;
67
79
  annotations: Record<string, string>;
68
80
  }
81
+ export type RoomAllocationStatus = "Allocated" | "Unallocated";
82
+ export interface RoomStatus {
83
+ status: RoomAllocationStatus;
84
+ allocatedAt?: Date | null;
85
+ runningForSeconds?: number | null;
86
+ }
87
+ export interface RoomLifecycleEvent {
88
+ id: string;
89
+ roomName: string;
90
+ sessionId?: string | null;
91
+ type: string;
92
+ message: string;
93
+ severity?: string | null;
94
+ createdAt: Date;
95
+ }
69
96
  export interface GroupInfo {
70
97
  id: string;
71
98
  name: string;
@@ -401,6 +428,7 @@ export interface ServiceSpec {
401
428
  version: "v1";
402
429
  kind: "Service";
403
430
  id?: string | null;
431
+ enabled?: boolean;
404
432
  metadata: ServiceMetadata;
405
433
  agents?: AgentSpec[] | null;
406
434
  ports?: PortSpec[];
@@ -578,6 +606,8 @@ export declare class Meshagent {
578
606
  private secretVersionPayload;
579
607
  private parseRoomSession;
580
608
  private parseRoom;
609
+ private parseRoomStatus;
610
+ private parseRoomLifecycleEvent;
581
611
  private parseGroup;
582
612
  private parseRoute;
583
613
  private parseFeed;
@@ -587,6 +617,7 @@ export declare class Meshagent {
587
617
  private parseAccessResource;
588
618
  private parseAccessSubject;
589
619
  private serializeAccessSubject;
620
+ private parseLlmDelegation;
590
621
  private serializeAccessResource;
591
622
  private parseProjectMember;
592
623
  private parseGroupMember;
@@ -900,6 +931,10 @@ export declare class Meshagent {
900
931
  annotations?: Record<string, string>;
901
932
  }): Promise<RoomInfo>;
902
933
  getRoom(projectId: string, name: string): Promise<RoomInfo>;
934
+ getRoomStatus(projectId: string, name: string): Promise<RoomStatus>;
935
+ listRoomEvents(projectId: string, name: string, options?: {
936
+ limit?: number;
937
+ }): Promise<RoomLifecycleEvent[]>;
903
938
  updateRoom(projectId: string, roomId: string, name: string, options?: {
904
939
  metadata?: Record<string, unknown>;
905
940
  annotations?: Record<string, string>;
@@ -949,6 +984,14 @@ export declare class Meshagent {
949
984
  }): Promise<void>;
950
985
  connectRoom(projectId: string, room: string): Promise<RoomConnectionInfo>;
951
986
  connectAgent(projectId: string, agentName: string): Promise<AgentConnectionInfo>;
987
+ connectLlm(params: {
988
+ projectId: string;
989
+ subject: AccessSubject;
990
+ maxBudget: string;
991
+ providers?: LlmProvider[];
992
+ models?: string[];
993
+ expiresInSeconds?: number;
994
+ }): Promise<LlmDelegation>;
952
995
  listRooms(projectId: string, options?: {
953
996
  pageSize?: number;
954
997
  continuationToken?: string;
@@ -83,7 +83,7 @@ function normalizeServiceSpec(service) {
83
83
  })),
84
84
  },
85
85
  };
86
- return { ...service, agents, container };
86
+ return { ...service, enabled: service.enabled ?? true, agents, container };
87
87
  }
88
88
  class ServiceTemplateSpec {
89
89
  constructor(template) {
@@ -199,6 +199,7 @@ function serializeServiceSpec(service) {
199
199
  };
200
200
  return pruneUndefinedValues({
201
201
  ...service,
202
+ enabled: service.enabled ?? true,
202
203
  container,
203
204
  agents,
204
205
  });
@@ -399,6 +400,54 @@ class Meshagent {
399
400
  annotations: annotations && typeof annotations === "object" ? annotations : {},
400
401
  };
401
402
  }
403
+ parseRoomStatus(data) {
404
+ if (!data || typeof data !== "object") {
405
+ throw new requirement_js_1.RoomException("Invalid room status payload");
406
+ }
407
+ const { status, allocated_at: allocatedAt, running_for_seconds: runningForSeconds, } = data;
408
+ if (status !== "Allocated" && status !== "Unallocated") {
409
+ throw new requirement_js_1.RoomException("Invalid room status payload: unknown status");
410
+ }
411
+ if (allocatedAt != null && typeof allocatedAt !== "string") {
412
+ throw new requirement_js_1.RoomException("Invalid room status payload: allocated_at must be a timestamp");
413
+ }
414
+ if (runningForSeconds != null && typeof runningForSeconds !== "number") {
415
+ throw new requirement_js_1.RoomException("Invalid room status payload: running_for_seconds must be a number");
416
+ }
417
+ return {
418
+ status,
419
+ allocatedAt: allocatedAt == null ? null : new Date(allocatedAt),
420
+ runningForSeconds: runningForSeconds == null ? null : runningForSeconds,
421
+ };
422
+ }
423
+ parseRoomLifecycleEvent(data) {
424
+ if (!data || typeof data !== "object") {
425
+ throw new requirement_js_1.RoomException("Invalid room lifecycle event payload");
426
+ }
427
+ const { id, room_name: roomName, session_id: sessionId, type, message, severity, created_at: createdAt, } = data;
428
+ if (typeof id !== "string"
429
+ || typeof roomName !== "string"
430
+ || typeof type !== "string"
431
+ || typeof message !== "string"
432
+ || typeof createdAt !== "string") {
433
+ throw new requirement_js_1.RoomException("Invalid room lifecycle event payload: missing required fields");
434
+ }
435
+ if (sessionId != null && typeof sessionId !== "string") {
436
+ throw new requirement_js_1.RoomException("Invalid room lifecycle event payload: session_id must be a string");
437
+ }
438
+ if (severity != null && typeof severity !== "string") {
439
+ throw new requirement_js_1.RoomException("Invalid room lifecycle event payload: severity must be a string");
440
+ }
441
+ return {
442
+ id,
443
+ roomName,
444
+ sessionId: sessionId == null ? null : sessionId,
445
+ type,
446
+ message,
447
+ severity: severity == null ? null : severity,
448
+ createdAt: new Date(createdAt),
449
+ };
450
+ }
402
451
  parseGroup(data) {
403
452
  if (!data || typeof data !== "object") {
404
453
  throw new requirement_js_1.RoomException("Invalid group payload");
@@ -595,7 +644,7 @@ class Meshagent {
595
644
  serializeAccessSubject(subject) {
596
645
  return {
597
646
  type: subject.type,
598
- id: subject.id,
647
+ ...(subject.id !== undefined ? { id: subject.id } : {}),
599
648
  ...(subject.name !== undefined ? { name: subject.name } : {}),
600
649
  ...(subject.firstName !== undefined ? { first_name: subject.firstName } : {}),
601
650
  ...(subject.lastName !== undefined ? { last_name: subject.lastName } : {}),
@@ -604,6 +653,24 @@ class Meshagent {
604
653
  ...(subject.relation !== undefined ? { relation: subject.relation } : {}),
605
654
  };
606
655
  }
656
+ parseLlmDelegation(data) {
657
+ if (!data || typeof data !== "object" || typeof data.id !== "string" || typeof data.token !== "string"
658
+ || typeof data.expires_at !== "string" || typeof data.project_id !== "string"
659
+ || typeof data.max_budget !== "string") {
660
+ throw new requirement_js_1.RoomException("Invalid LLM delegation payload");
661
+ }
662
+ return {
663
+ id: data.id,
664
+ token: data.token,
665
+ expiresAt: data.expires_at,
666
+ projectId: data.project_id,
667
+ delegator: this.parseAccessSubject(data.delegator),
668
+ subject: this.parseAccessSubject(data.subject),
669
+ providers: Array.isArray(data.providers) ? data.providers : null,
670
+ models: Array.isArray(data.models) ? data.models.filter((value) => typeof value === "string") : null,
671
+ maxBudget: data.max_budget,
672
+ };
673
+ }
607
674
  serializeAccessResource(resource) {
608
675
  return {
609
676
  type: resource.type,
@@ -724,6 +791,9 @@ class Meshagent {
724
791
  metadata: parsedResource.metadata ?? {},
725
792
  annotations: parsedResource.annotations ?? {},
726
793
  };
794
+ if (!parsedSubject.id) {
795
+ throw new requirement_js_1.RoomException("Invalid room grant payload: missing subject id");
796
+ }
727
797
  return {
728
798
  resource: parsedResource,
729
799
  subject: parsedSubject,
@@ -1770,6 +1840,22 @@ class Meshagent {
1770
1840
  });
1771
1841
  return this.parseRoom(data);
1772
1842
  }
1843
+ async getRoomStatus(projectId, name) {
1844
+ const roomName = this.encodePathComponent(name);
1845
+ const data = await this.request(`/accounts/projects/${projectId}/rooms/${roomName}/status`, {
1846
+ action: "get room status",
1847
+ });
1848
+ return this.parseRoomStatus(data);
1849
+ }
1850
+ async listRoomEvents(projectId, name, options = {}) {
1851
+ const roomName = this.encodePathComponent(name);
1852
+ const data = await this.request(`/accounts/projects/${projectId}/rooms/${roomName}/events`, {
1853
+ query: { limit: options.limit ?? 100 },
1854
+ action: "list room lifecycle events",
1855
+ });
1856
+ const events = Array.isArray(data?.events) ? data.events : [];
1857
+ return events.map((event) => this.parseRoomLifecycleEvent(event));
1858
+ }
1773
1859
  async updateRoom(projectId, roomId, name, options = {}) {
1774
1860
  const payload = { name };
1775
1861
  if (options.metadata !== undefined) {
@@ -1893,6 +1979,21 @@ class Meshagent {
1893
1979
  });
1894
1980
  return this.parseAgentConnectionInfo(data);
1895
1981
  }
1982
+ async connectLlm(params) {
1983
+ const data = await this.request("/llm/connect", {
1984
+ method: "POST",
1985
+ headers: { "Meshagent-Project-Id": params.projectId },
1986
+ json: {
1987
+ subject: this.serializeAccessSubject(params.subject),
1988
+ max_budget: params.maxBudget,
1989
+ ...(params.providers !== undefined ? { providers: params.providers } : {}),
1990
+ ...(params.models !== undefined ? { models: params.models } : {}),
1991
+ ...(params.expiresInSeconds !== undefined ? { expires_in_seconds: params.expiresInSeconds } : {}),
1992
+ },
1993
+ action: "connect LLM delegation",
1994
+ });
1995
+ return this.parseLlmDelegation(data);
1996
+ }
1896
1997
  async listRooms(projectId, options = {}) {
1897
1998
  const { pageSize = 50, continuationToken, filter, view } = options;
1898
1999
  const data = await this.request(`/accounts/projects/${projectId}/rooms`, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meshagent/meshagent",
3
- "version": "0.49.1",
3
+ "version": "0.51.0",
4
4
  "description": "Meshagent Client",
5
5
  "homepage": "https://github.com/meshagent/meshagent-ts",
6
6
  "scripts": {