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

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,36 @@ 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. Consumers choose room types and optional capacity; component coordinates and Three.js objects stay internal to the SDK.
83
+
56
84
  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
85
 
58
86
  ```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,24 @@ 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. `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.
170
+
171
+ `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.
172
+
161
173
  ## React Office View
162
174
 
163
175
  Use `AgentGameOfficeView` when embedding the office view in a React application.
164
176
 
165
177
  ```tsx
178
+ import { useState } from "react";
166
179
  import { AgentGameRuntimeBrowserClient } from "@agent-os-lab/agent-game-sdk";
180
+ import type { AgentGameOfficeController } from "@agent-os-lab/agent-game-sdk/office";
167
181
  import { AgentGameOfficeView } from "@agent-os-lab/agent-game-sdk/office/react";
168
182
 
169
183
  const client = new AgentGameRuntimeBrowserClient({
@@ -171,18 +185,34 @@ const client = new AgentGameRuntimeBrowserClient({
171
185
  });
172
186
 
173
187
  export function Office() {
188
+ const [view, setView] = useState<AgentGameOfficeController | null>(null);
189
+
174
190
  return (
175
- <AgentGameOfficeView
176
- renderer="three"
177
- source={{ type: "runtime", client }}
178
- focusedAgentId="agent-1"
179
- style={{ height: 640 }}
180
- />
191
+ <>
192
+ <button type="button" onClick={() => view?.refreshAgents()}>
193
+ Refresh agents
194
+ </button>
195
+ <AgentGameOfficeView
196
+ renderer="three"
197
+ office={{
198
+ rooms: [
199
+ { type: "office" },
200
+ { type: "auditorium" },
201
+ { type: "gym" },
202
+ ],
203
+ }}
204
+ source={{ type: "runtime", client }}
205
+ focusedAgentId="agent-1"
206
+ style={{ height: 640 }}
207
+ onReady={setView}
208
+ onDestroy={() => setView(null)}
209
+ />
210
+ </>
181
211
  );
182
212
  }
183
213
  ```
184
214
 
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.
215
+ 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
216
 
187
217
  ## Snapshot Source
188
218
 
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.4",
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";