@agent-os-lab/agent-game-sdk 0.1.3 → 0.1.5

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/README.md CHANGED
@@ -20,6 +20,13 @@ const client = new AgentGameRuntimeBrowserClient({
20
20
 
21
21
  const view = await mountAgentGameOffice(container, {
22
22
  renderer: "three",
23
+ office: {
24
+ rooms: [
25
+ { type: "office" },
26
+ { type: "auditorium", capacity: 40 },
27
+ { type: "gym" },
28
+ ],
29
+ },
23
30
  source: {
24
31
  type: "runtime",
25
32
  client,
@@ -27,13 +34,16 @@ const view = await mountAgentGameOffice(container, {
27
34
  });
28
35
 
29
36
  view.focusAgent("agent-1");
37
+ view.refreshAgents();
30
38
  view.destroy();
31
39
  ```
32
40
 
33
41
  React wrapper:
34
42
 
35
43
  ```tsx
44
+ import { useState } from "react";
36
45
  import { AgentGameRuntimeBrowserClient } from "@agent-os-lab/agent-game-sdk";
46
+ import type { AgentGameOfficeController } from "@agent-os-lab/agent-game-sdk/office";
37
47
  import { AgentGameOfficeView } from "@agent-os-lab/agent-game-sdk/office/react";
38
48
 
39
49
  const client = new AgentGameRuntimeBrowserClient({
@@ -41,18 +51,47 @@ const client = new AgentGameRuntimeBrowserClient({
41
51
  });
42
52
 
43
53
  export function Office() {
54
+ const [view, setView] = useState<AgentGameOfficeController | null>(null);
55
+
44
56
  return (
45
- <AgentGameOfficeView
46
- renderer="three"
47
- source={{ type: "runtime", client }}
48
- style={{ height: 640 }}
49
- />
57
+ <>
58
+ <button type="button" onClick={() => view?.refreshAgents()}>
59
+ Refresh agents
60
+ </button>
61
+ <AgentGameOfficeView
62
+ renderer="three"
63
+ office={{
64
+ rooms: [
65
+ { type: "office" },
66
+ { type: "auditorium" },
67
+ { type: "gym" },
68
+ ],
69
+ }}
70
+ source={{ type: "runtime", client }}
71
+ style={{ height: 640 }}
72
+ onReady={setView}
73
+ onDestroy={() => setView(null)}
74
+ />
75
+ </>
50
76
  );
51
77
  }
52
78
  ```
53
79
 
54
80
  `agent-game-sdk/office` is renderer and framework neutral. `agent-game-sdk/office/react` is the React-only entrypoint.
55
81
 
82
+ The built-in 3D renderer supports semantic room configuration. If `office` is omitted, the SDK renders the default `office + auditorium + gym` layout. To choose visible rooms, pass `office.rooms` in the order you want them assembled:
83
+
84
+ ```ts
85
+ office: {
86
+ rooms: [
87
+ { type: "office" },
88
+ { type: "gym" },
89
+ ],
90
+ }
91
+ ```
92
+
93
+ Built-in room types are `office`, `auditorium`, and `gym`. `capacity` is optional and affects generated agent placement anchors; desks, walls, meeting rooms, gym equipment, windows, and raw coordinates stay internal to the SDK.
94
+
56
95
  Browser clients should call an application BFF endpoint. Keep the AgentOS service API key on the server; the SDK server client forwards it to Agent Game Runtime:
57
96
 
58
97
  ```ts
package/USAGE.md CHANGED
@@ -146,6 +146,13 @@ const client = new AgentGameRuntimeBrowserClient({
146
146
 
147
147
  const view = await mountAgentGameOffice(container, {
148
148
  renderer: "three",
149
+ office: {
150
+ rooms: [
151
+ { type: "office", capacity: 12 },
152
+ { type: "auditorium", capacity: 40 },
153
+ { type: "gym", capacity: 8 },
154
+ ],
155
+ },
149
156
  source: {
150
157
  type: "runtime",
151
158
  client,
@@ -153,17 +160,32 @@ const view = await mountAgentGameOffice(container, {
153
160
  });
154
161
 
155
162
  view.focusAgent("agent-1");
163
+ view.refreshAgents();
156
164
  view.destroy();
157
165
  ```
158
166
 
159
167
  `renderer: "three"` is the built-in renderer and the default renderer. The container must have a stable size; the React wrapper supplies a default `minHeight`, but framework-neutral callers should size the container in CSS.
160
168
 
169
+ `office.rooms` configures the 3D office by semantic room type. The built-in room types are `office`, `auditorium`, and `gym`. If `office` is omitted, the SDK renders all three rooms. If `office.rooms` is provided, only those rooms render, in the provided order:
170
+
171
+ ```ts
172
+ office: {
173
+ rooms: [{ type: "office" }, { type: "gym" }],
174
+ }
175
+ ```
176
+
177
+ The layout packs up to three rooms per row, then starts another row. `capacity` is optional and influences the generated anchors used for agent placement. Do not configure desks, walls, whiteboards, fitness equipment, or raw coordinates from application code; those components remain SDK-managed presets.
178
+
179
+ `refreshAgents` asks Agent Game Runtime to refresh the tenant roster through the existing bootstrap flow. It is intended for UI controls such as a refresh button after an Agent was created or deleted in another surface.
180
+
161
181
  ## React Office View
162
182
 
163
183
  Use `AgentGameOfficeView` when embedding the office view in a React application.
164
184
 
165
185
  ```tsx
186
+ import { useState } from "react";
166
187
  import { AgentGameRuntimeBrowserClient } from "@agent-os-lab/agent-game-sdk";
188
+ import type { AgentGameOfficeController } from "@agent-os-lab/agent-game-sdk/office";
167
189
  import { AgentGameOfficeView } from "@agent-os-lab/agent-game-sdk/office/react";
168
190
 
169
191
  const client = new AgentGameRuntimeBrowserClient({
@@ -171,18 +193,34 @@ const client = new AgentGameRuntimeBrowserClient({
171
193
  });
172
194
 
173
195
  export function Office() {
196
+ const [view, setView] = useState<AgentGameOfficeController | null>(null);
197
+
174
198
  return (
175
- <AgentGameOfficeView
176
- renderer="three"
177
- source={{ type: "runtime", client }}
178
- focusedAgentId="agent-1"
179
- style={{ height: 640 }}
180
- />
199
+ <>
200
+ <button type="button" onClick={() => view?.refreshAgents()}>
201
+ Refresh agents
202
+ </button>
203
+ <AgentGameOfficeView
204
+ renderer="three"
205
+ office={{
206
+ rooms: [
207
+ { type: "office" },
208
+ { type: "auditorium" },
209
+ { type: "gym" },
210
+ ],
211
+ }}
212
+ source={{ type: "runtime", client }}
213
+ focusedAgentId="agent-1"
214
+ style={{ height: 640 }}
215
+ onReady={setView}
216
+ onDestroy={() => setView(null)}
217
+ />
218
+ </>
181
219
  );
182
220
  }
183
221
  ```
184
222
 
185
- Keep `source` object identity stable across renders when possible. Recreating `source` every render can remount the view because the React wrapper treats `options.source` as an effect dependency.
223
+ Keep `source` object identity stable across renders when possible. Recreating `source` every render can remount the view because the React wrapper treats it as an effect dependency. Equivalent inline `office` objects do not remount the view, but memoizing office config is still preferable when constructing it dynamically.
186
224
 
187
225
  ## Snapshot Source
188
226
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-os-lab/agent-game-sdk",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "src",
@@ -5,6 +5,10 @@ import type {
5
5
  AgentPresenceStatus,
6
6
  GameRuntimeSubscription,
7
7
  } from "../../runtime-client";
8
+ import type {
9
+ AgentGameOfficeConfig,
10
+ ResolvedOfficeLayout,
11
+ } from "../layout";
8
12
 
9
13
  export type {
10
14
  AgentActivityDisplay,
@@ -95,16 +99,19 @@ export type AgentGameOfficeRenderer = {
95
99
  export type AgentGameOfficeMountOptions = {
96
100
  renderer?: AgentGameOfficeRendererKind | AgentGameOfficeRenderer;
97
101
  source: AgentGameOfficeSourceInput;
102
+ office?: AgentGameOfficeConfig;
98
103
  focusedAgentId?: string | null;
99
104
  className?: string;
100
105
  };
101
106
 
102
107
  export type AgentGameOfficeResolvedOptions = Omit<AgentGameOfficeMountOptions, "renderer"> & {
103
108
  renderer: AgentGameOfficeRendererKind | AgentGameOfficeRenderer;
109
+ officeLayout: ResolvedOfficeLayout;
104
110
  };
105
111
 
106
112
  export type AgentGameOfficeController = {
107
113
  updateAgents(agents: AgentPresence[]): void;
108
114
  focusAgent(agentId: string | null): void;
115
+ refreshAgents(): void;
109
116
  destroy(): void;
110
117
  };
@@ -1,4 +1,5 @@
1
1
  export * from "./core/types";
2
2
  export * from "./core/projection";
3
3
  export * from "./core/source";
4
+ export * from "./layout";
4
5
  export * from "./mount";
@@ -0,0 +1,76 @@
1
+ export type AgentGameOfficeRoomType = "office" | "auditorium" | "gym";
2
+
3
+ export type AgentGameOfficeRoomConfig = {
4
+ type: AgentGameOfficeRoomType;
5
+ capacity?: number;
6
+ };
7
+
8
+ export type AgentGameOfficeConfig = {
9
+ rooms: AgentGameOfficeRoomConfig[];
10
+ };
11
+
12
+ export type NormalizedOfficeRoomConfig = {
13
+ id: string;
14
+ type: AgentGameOfficeRoomType;
15
+ capacity: number;
16
+ };
17
+
18
+ export type NormalizedOfficeConfig = {
19
+ rooms: NormalizedOfficeRoomConfig[];
20
+ };
21
+
22
+ const DEFAULT_ROOM_CAPACITY = {
23
+ office: 12,
24
+ auditorium: 40,
25
+ gym: 8,
26
+ } satisfies Record<AgentGameOfficeRoomType, number>;
27
+
28
+ const MAX_ROOM_CAPACITY = {
29
+ office: 48,
30
+ auditorium: 120,
31
+ gym: 24,
32
+ } satisfies Record<AgentGameOfficeRoomType, number>;
33
+
34
+ export const DEFAULT_OFFICE_CONFIG: AgentGameOfficeConfig = {
35
+ rooms: [
36
+ { type: "office" },
37
+ { type: "auditorium" },
38
+ { type: "gym" },
39
+ ],
40
+ };
41
+
42
+ export function normalizeOfficeConfig(
43
+ config: AgentGameOfficeConfig | undefined = DEFAULT_OFFICE_CONFIG,
44
+ ): NormalizedOfficeConfig {
45
+ if (!Array.isArray(config.rooms) || config.rooms.length === 0) {
46
+ throw new Error("Agent game office config requires at least one room");
47
+ }
48
+
49
+ const counts = new Map<AgentGameOfficeRoomType, number>();
50
+ return {
51
+ rooms: config.rooms.map((room) => {
52
+ assertRoomType(room.type);
53
+ const nextCount = (counts.get(room.type) ?? 0) + 1;
54
+ counts.set(room.type, nextCount);
55
+ return {
56
+ id: `${room.type}-${nextCount}`,
57
+ type: room.type,
58
+ capacity: normalizeRoomCapacity(room.type, room.capacity),
59
+ };
60
+ }),
61
+ };
62
+ }
63
+
64
+ function assertRoomType(value: string): asserts value is AgentGameOfficeRoomType {
65
+ if (value !== "office" && value !== "auditorium" && value !== "gym") {
66
+ throw new Error(`Unsupported agent game office room type: ${value}`);
67
+ }
68
+ }
69
+
70
+ function normalizeRoomCapacity(type: AgentGameOfficeRoomType, capacity: number | undefined): number {
71
+ const value = capacity ?? DEFAULT_ROOM_CAPACITY[type];
72
+ if (!Number.isInteger(value) || value <= 0) {
73
+ throw new Error(`Agent game office room ${type} capacity must be a positive integer`);
74
+ }
75
+ return Math.min(value, MAX_ROOM_CAPACITY[type]);
76
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./config";
2
+ export * from "./resolver";