@iniesta8888/agent-live 0.3.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 (182) hide show
  1. package/CODE_OF_CONDUCT.md +7 -0
  2. package/CONTRIBUTING.md +56 -0
  3. package/LICENSE +21 -0
  4. package/README.md +92 -0
  5. package/SECURITY.md +13 -0
  6. package/dist/adapter-sdk/index.d.ts +45 -0
  7. package/dist/adapter-sdk/index.d.ts.map +1 -0
  8. package/dist/adapter-sdk/index.js +106 -0
  9. package/dist/adapter-sdk/index.js.map +1 -0
  10. package/dist/content/compiler.d.ts +31 -0
  11. package/dist/content/compiler.d.ts.map +1 -0
  12. package/dist/content/compiler.js +218 -0
  13. package/dist/content/compiler.js.map +1 -0
  14. package/dist/content/graph-validator.d.ts +56 -0
  15. package/dist/content/graph-validator.d.ts.map +1 -0
  16. package/dist/content/graph-validator.js +226 -0
  17. package/dist/content/graph-validator.js.map +1 -0
  18. package/dist/content/library.d.ts +4 -0
  19. package/dist/content/library.d.ts.map +1 -0
  20. package/dist/content/library.js +45 -0
  21. package/dist/content/library.js.map +1 -0
  22. package/dist/content/registry.d.ts +34 -0
  23. package/dist/content/registry.d.ts.map +1 -0
  24. package/dist/content/registry.js +130 -0
  25. package/dist/content/registry.js.map +1 -0
  26. package/dist/content/runtime-content.d.ts +63 -0
  27. package/dist/content/runtime-content.d.ts.map +1 -0
  28. package/dist/content/runtime-content.js +78 -0
  29. package/dist/content/runtime-content.js.map +1 -0
  30. package/dist/content/schema.d.ts +142 -0
  31. package/dist/content/schema.d.ts.map +1 -0
  32. package/dist/content/schema.js +280 -0
  33. package/dist/content/schema.js.map +1 -0
  34. package/dist/content/validator.d.ts +35 -0
  35. package/dist/content/validator.d.ts.map +1 -0
  36. package/dist/content/validator.js +205 -0
  37. package/dist/content/validator.js.map +1 -0
  38. package/dist/core/agents.d.ts +56 -0
  39. package/dist/core/agents.d.ts.map +1 -0
  40. package/dist/core/agents.js +148 -0
  41. package/dist/core/agents.js.map +1 -0
  42. package/dist/core/limits.d.ts +15 -0
  43. package/dist/core/limits.d.ts.map +1 -0
  44. package/dist/core/limits.js +16 -0
  45. package/dist/core/limits.js.map +1 -0
  46. package/dist/core/mapping.d.ts +17 -0
  47. package/dist/core/mapping.d.ts.map +1 -0
  48. package/dist/core/mapping.js +94 -0
  49. package/dist/core/mapping.js.map +1 -0
  50. package/dist/core/protocol.d.ts +105 -0
  51. package/dist/core/protocol.d.ts.map +1 -0
  52. package/dist/core/protocol.js +6 -0
  53. package/dist/core/protocol.js.map +1 -0
  54. package/dist/core/state.d.ts +49 -0
  55. package/dist/core/state.d.ts.map +1 -0
  56. package/dist/core/state.js +216 -0
  57. package/dist/core/state.js.map +1 -0
  58. package/dist/creator/commands.d.ts +19 -0
  59. package/dist/creator/commands.d.ts.map +1 -0
  60. package/dist/creator/commands.js +44 -0
  61. package/dist/creator/commands.js.map +1 -0
  62. package/dist/creator/mode.d.ts +10 -0
  63. package/dist/creator/mode.d.ts.map +1 -0
  64. package/dist/creator/mode.js +23 -0
  65. package/dist/creator/mode.js.map +1 -0
  66. package/dist/creator/service.d.ts +199 -0
  67. package/dist/creator/service.d.ts.map +1 -0
  68. package/dist/creator/service.js +159 -0
  69. package/dist/creator/service.js.map +1 -0
  70. package/dist/index.d.ts +14 -0
  71. package/dist/index.d.ts.map +1 -0
  72. package/dist/index.js +10 -0
  73. package/dist/index.js.map +1 -0
  74. package/dist/runtime/agent-live-runtime.d.ts +17 -0
  75. package/dist/runtime/agent-live-runtime.d.ts.map +1 -0
  76. package/dist/runtime/agent-live-runtime.js +50 -0
  77. package/dist/runtime/agent-live-runtime.js.map +1 -0
  78. package/dist/runtime/content-service.d.ts +75 -0
  79. package/dist/runtime/content-service.d.ts.map +1 -0
  80. package/dist/runtime/content-service.js +60 -0
  81. package/dist/runtime/content-service.js.map +1 -0
  82. package/dist/runtime/resource-guard.d.ts +17 -0
  83. package/dist/runtime/resource-guard.d.ts.map +1 -0
  84. package/dist/runtime/resource-guard.js +54 -0
  85. package/dist/runtime/resource-guard.js.map +1 -0
  86. package/dist/runtime/server.d.ts +39 -0
  87. package/dist/runtime/server.d.ts.map +1 -0
  88. package/dist/runtime/server.js +286 -0
  89. package/dist/runtime/server.js.map +1 -0
  90. package/dist/web/app.d.ts +1 -0
  91. package/dist/web/app.js +1317 -0
  92. package/dist/web/index.html +45 -0
  93. package/dist/web/office.js +350 -0
  94. package/dist/web/sprites.js +185 -0
  95. package/dist/web/style.css +288 -0
  96. package/dist/web/v2/bootstrap.js +276 -0
  97. package/dist/web/v2/content/README.md +17 -0
  98. package/dist/web/v2/content/agent-skins/studio-team.json +33 -0
  99. package/dist/web/v2/content/agent-skins/tiny-developers.json +33 -0
  100. package/dist/web/v2/content/atmospheres/default.json +13 -0
  101. package/dist/web/v2/content/atmospheres/rainy-night.json +37 -0
  102. package/dist/web/v2/content/catalog.json +14 -0
  103. package/dist/web/v2/content/component-library/activity-implementations.json +873 -0
  104. package/dist/web/v2/content/component-library/activity-recipes.json +25 -0
  105. package/dist/web/v2/content/component-library/agent-profile-templates.json +18 -0
  106. package/dist/web/v2/content/component-library/catalog.json +38 -0
  107. package/dist/web/v2/content/component-library/npc-templates.json +42 -0
  108. package/dist/web/v2/content/component-library/props.json +41 -0
  109. package/dist/web/v2/content/environments/local-office.json +31 -0
  110. package/dist/web/v2/content/environments/rainy-night.json +28 -0
  111. package/dist/web/v2/content/environments/static-office.json +27 -0
  112. package/dist/web/v2/content/layouts/boardroom-office.json +122 -0
  113. package/dist/web/v2/content/layouts/demo-office.json +88 -0
  114. package/dist/web/v2/content/layouts/lively-office.json +96 -0
  115. package/dist/web/v2/content/layouts/old-school-office.json +154 -0
  116. package/dist/web/v2/content/layouts/tech-open-office.json +132 -0
  117. package/dist/web/v2/content/life-activities/boardroom-routines.json +67 -0
  118. package/dist/web/v2/content/life-activities/none.json +10 -0
  119. package/dist/web/v2/content/life-activities/office-basics.json +39 -0
  120. package/dist/web/v2/content/life-activities/old-school-routines.json +74 -0
  121. package/dist/web/v2/content/life-activities/tech-office-routines.json +148 -0
  122. package/dist/web/v2/content/npcs/boardroom-staff.json +54 -0
  123. package/dist/web/v2/content/npcs/none.json +10 -0
  124. package/dist/web/v2/content/npcs/office-staff.json +25 -0
  125. package/dist/web/v2/content/npcs/old-school-staff.json +39 -0
  126. package/dist/web/v2/content/npcs/tech-office-staff.json +40 -0
  127. package/dist/web/v2/content/official-offices/boardroom-office.json +25 -0
  128. package/dist/web/v2/content/official-offices/old-school-office.json +25 -0
  129. package/dist/web/v2/content/official-offices/tech-open-office.json +25 -0
  130. package/dist/web/v2/content/presets/boardroom-office.json +21 -0
  131. package/dist/web/v2/content/presets/cozy-studio.json +19 -0
  132. package/dist/web/v2/content/presets/demo-office.json +19 -0
  133. package/dist/web/v2/content/presets/lively-office.json +19 -0
  134. package/dist/web/v2/content/presets/night-shift.json +19 -0
  135. package/dist/web/v2/content/presets/old-school-office.json +20 -0
  136. package/dist/web/v2/content/presets/refined-demo.json +20 -0
  137. package/dist/web/v2/content/presets/tech-open-office.json +21 -0
  138. package/dist/web/v2/content/props/default-office.json +23 -0
  139. package/dist/web/v2/content/props/extended-office.json +39 -0
  140. package/dist/web/v2/content/props/tech-office.json +28 -0
  141. package/dist/web/v2/content/styles/pixel-classic.json +160 -0
  142. package/dist/web/v2/content/styles/warm-studio.json +150 -0
  143. package/dist/web/v2/environment-runtime.d.ts +1 -0
  144. package/dist/web/v2/environment-runtime.js +138 -0
  145. package/dist/web/v2/graph-validator.d.ts +55 -0
  146. package/dist/web/v2/graph-validator.js +225 -0
  147. package/dist/web/v2/i18n.js +54 -0
  148. package/dist/web/v2/locales/en.json +209 -0
  149. package/dist/web/v2/locales/zh-CN.json +52 -0
  150. package/dist/web/v2/office-engine.d.ts +1 -0
  151. package/dist/web/v2/office-engine.js +145 -0
  152. package/dist/web/v2/office-renderer.d.ts +1 -0
  153. package/dist/web/v2/office-renderer.js +843 -0
  154. package/dist/web/v2/parity.html +10 -0
  155. package/dist/web/v2/parity.js +82 -0
  156. package/dist/web/v2/sprite-renderer.d.ts +1 -0
  157. package/dist/web/v2/sprite-renderer.js +242 -0
  158. package/dist/web/v2/static-content.js +48 -0
  159. package/dist/web/v2/style.css +140 -0
  160. package/dist/web/v2.html +68 -0
  161. package/docs/ADAPTER-DEVELOPMENT.md +328 -0
  162. package/docs/ADAPTER-SDK.md +109 -0
  163. package/docs/ARCHITECTURE.md +223 -0
  164. package/docs/COMPONENT-LIBRARY.md +212 -0
  165. package/docs/CUSTOMIZATION.md +163 -0
  166. package/docs/DEVELOPER.md +186 -0
  167. package/docs/DSH-ADAPTER-DESIGN.md +173 -0
  168. package/docs/OFFICE-THEMES.md +516 -0
  169. package/docs/PRESET-CONFIG.md +460 -0
  170. package/docs/RELEASE-CHECK.md +23 -0
  171. package/docs/TECHNICAL.md +515 -0
  172. package/docs/USING-CODEX.md +24 -0
  173. package/docs/USING-DSH.md +44 -0
  174. package/docs/USING-PI.md +50 -0
  175. package/docs/VISION.md +146 -0
  176. package/examples/adapter/local-office.mjs +52 -0
  177. package/package.json +89 -0
  178. package/skills/agent-live-adapter-builder/SKILL.md +30 -0
  179. package/skills/agent-live-adapter-builder/agents/openai.yaml +4 -0
  180. package/skills/agent-live-adapter-builder/references/investigation.md +9 -0
  181. package/skills/agent-live-adapter-builder/references/review.md +7 -0
  182. package/skills/agent-live-adapter-builder/scripts/create-adapter.mjs +26 -0
@@ -0,0 +1,10 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head><meta charset="utf-8" /><title>Agent Live V2 Parity</title></head>
4
+ <body>
5
+ <pre id="result">RUNNING</pre>
6
+ <script src="/office.js"></script>
7
+ <script src="/sprites.js"></script>
8
+ <script type="module" src="/v2/parity.js"></script>
9
+ </body>
10
+ </html>
@@ -0,0 +1,82 @@
1
+ import { createOfficeRenderer } from "./office-renderer.js";
2
+ import { createSpriteRenderer } from "./sprite-renderer.js";
3
+ import { createEnvironmentRuntime } from "./environment-runtime.js";
4
+
5
+ const legacyOffice = window.Office;
6
+ const legacySprites = window.Sprites;
7
+ const root = "/v2/content";
8
+ const read = async (path) => (await fetch(`${root}/${path}`)).json();
9
+
10
+ function canvas(width, height) {
11
+ const node = document.createElement("canvas");
12
+ node.width = width;
13
+ node.height = height;
14
+ return node;
15
+ }
16
+
17
+ function pixelDiff(a, b) {
18
+ const left = a.getContext("2d").getImageData(0, 0, a.width, a.height).data;
19
+ const right = b.getContext("2d").getImageData(0, 0, b.width, b.height).data;
20
+ let changed = 0;
21
+ for (let i = 0; i < left.length; i++) if (left[i] !== right[i]) changed++;
22
+ return changed;
23
+ }
24
+
25
+ const [style, layout, agentSkin, props, npcs, lifeActivities, atmosphere, environment, preset] = await Promise.all([
26
+ read("styles/pixel-classic.json"),
27
+ read("layouts/demo-office.json"),
28
+ read("agent-skins/tiny-developers.json"),
29
+ read("props/default-office.json"),
30
+ read("npcs/none.json"),
31
+ read("life-activities/none.json"),
32
+ read("atmospheres/default.json"),
33
+ read("environments/static-office.json"),
34
+ read("presets/demo-office.json"),
35
+ ]);
36
+ const content = { style, layout, agentSkin, props, npcs, lifeActivities, atmosphere, environment, preset };
37
+ const nativeOffice = createOfficeRenderer(content, createEnvironmentRuntime(environment));
38
+ const nativeSprites = createSpriteRenderer(content);
39
+ const results = [];
40
+
41
+ for (const test of [
42
+ { name: "room-idle", t: 0, hot: [], occupied: [] },
43
+ { name: "room-desks", t: 777, hot: ["desk0", "desk5"], occupied: [0, 1, 5] },
44
+ { name: "room-archive", t: 1733, hot: ["archive"], occupied: [2] },
45
+ { name: "room-server", t: 2345, hot: ["server"], occupied: [4, 6] },
46
+ { name: "room-board-phone-coffee", t: 3891, hot: ["whiteboard", "phone", "coffee"], occupied: [7] },
47
+ ]) {
48
+ const oldCanvas = canvas(384, 216);
49
+ const newCanvas = canvas(384, 216);
50
+ legacyOffice.drawRoom(oldCanvas.getContext("2d"), test.t, new Set(test.hot), new Set(test.occupied));
51
+ nativeOffice.drawRoom(newCanvas.getContext("2d"), test.t, new Set(test.hot), new Set(test.occupied));
52
+ results.push({ name: test.name, changedChannels: pixelDiff(oldCanvas, newCanvas) });
53
+ }
54
+
55
+ for (const test of [
56
+ { name: "actor-lead", id: "main", role: "阿派", lead: true, state: "thinking", pose: "sit", dir: "up", t: 800 },
57
+ { name: "actor-scout", id: "scout", role: "scout", lead: false, state: "working", pose: "walk", dir: "right", t: 1400 },
58
+ { name: "actor-planner", id: "planner", role: "planner", lead: false, state: "done", pose: "talk", dir: "left", t: 2300 },
59
+ ]) {
60
+ const oldCanvas = canvas(48, 48);
61
+ const newCanvas = canvas(48, 48);
62
+ const base = { id: test.id, name: test.role, x: 24, y: 38, state: test.state, pose: test.pose, dir: test.dir, seed: 2, walkPhase: 0.42 };
63
+ legacySprites.drawCharacter(oldCanvas.getContext("2d"), { ...base, palette: legacySprites.paletteFor(test.id, test.role, test.lead) }, test.t);
64
+ nativeSprites.drawCharacter(newCanvas.getContext("2d"), { ...base, palette: nativeSprites.paletteFor(test.id, test.role, test.lead) }, test.t);
65
+ results.push({ name: test.name, changedChannels: pixelDiff(oldCanvas, newCanvas) });
66
+ }
67
+
68
+ for (const [index, kind] of ["key", "paper", "check", "bang", "cross", "spark", "unknown"].entries()) {
69
+ const oldCanvas = canvas(24, 24);
70
+ const newCanvas = canvas(24, 24);
71
+ const particle = { kind, x: 12, y: 12, life: 0.7, maxLife: 1 };
72
+ legacySprites.drawParticle(oldCanvas.getContext("2d"), { ...particle });
73
+ nativeSprites.drawParticle(newCanvas.getContext("2d"), { ...particle });
74
+ results.push({ name: `particle-${index}-${kind}`, changedChannels: pixelDiff(oldCanvas, newCanvas) });
75
+ }
76
+
77
+ const failures = results.filter((result) => result.changedChannels !== 0);
78
+ const output = document.getElementById("result");
79
+ output.textContent = failures.length
80
+ ? `FAIL\n${failures.map((failure) => `${failure.name}: ${failure.changedChannels}`).join("\n")}`
81
+ : `PASS ${results.length} pixel parity cases`;
82
+ document.documentElement.dataset.parity = failures.length ? "fail" : "pass";
@@ -0,0 +1 @@
1
+ export function createSpriteRenderer(content: unknown): unknown;
@@ -0,0 +1,242 @@
1
+ /** Build the V2 character renderer from Agent Skin and Style content. */
2
+ export function createSpriteRenderer(content) {
3
+ const skin = content.agentSkin;
4
+ const base = content.style.tokens.character;
5
+ const override = content.atmosphere.styleOverrides?.character ?? {};
6
+ const V = {
7
+ ...base,
8
+ ...override,
9
+ pips: { ...base.pips, ...(override.pips ?? {}) },
10
+ particles: { ...base.particles, ...(override.particles ?? {}) },
11
+ };
12
+ const rich = content.preset.render?.detail === "rich" || V.detail === "rich";
13
+ const px = (c, x, y, w, h, color) => {
14
+ c.fillStyle = color;
15
+ c.fillRect(x | 0, y | 0, w | 0, h | 0);
16
+ };
17
+
18
+ function hash(text) {
19
+ let value = 2166136261;
20
+ for (let i = 0; i < text.length; i++) {
21
+ value ^= text.charCodeAt(i);
22
+ value = (value * 16777619) >>> 0;
23
+ }
24
+ return value;
25
+ }
26
+
27
+ function roleFor(name) {
28
+ return skin.roles[String(name ?? "").toLowerCase()] ?? null;
29
+ }
30
+
31
+ function paletteFor(id, name, isLead) {
32
+ const value = hash(`${id}|${name}`);
33
+ const role = roleFor(name);
34
+ return {
35
+ skin: skin.palettes.skin[value % skin.palettes.skin.length],
36
+ hair: skin.palettes.hair[(value >>> 3) % skin.palettes.hair.length],
37
+ shirt: role ? role.shirt : skin.palettes.fallbackShirts[(value >>> 6) % skin.palettes.fallbackShirts.length],
38
+ trim: role ? role.trim : skin.palettes.defaultTrim,
39
+ badge: isLead ? skin.palettes.leadBadge : skin.palettes.agentBadge,
40
+ };
41
+ }
42
+
43
+ function drawRichCharacter(c, actor, t) {
44
+ const p = actor.palette;
45
+ const walking = actor.pose === "walk";
46
+ const sitting = actor.pose === "sit" || actor.pose === "type";
47
+ const step = walking ? (((actor.walkPhase / 0.14) | 0) % 2) : 0;
48
+ const bob = walking ? step : Math.sin(t / 680 + actor.seed) > 0.72 ? 1 : 0;
49
+ const y = (actor.y | 0) - (sitting ? 3 : 0) + (sitting ? 0 : bob);
50
+ const x = actor.x | 0;
51
+ const dir = actor.dir ?? "down";
52
+ const outline = V.outline ?? V.shoes;
53
+ const skinShade = V.skinShade ?? p.skin;
54
+
55
+ px(c, x - 7, y - 1, 14, 2, V.shadow);
56
+ px(c, x - 5, y, 10, 1, V.shadow);
57
+ if (!sitting) {
58
+ const left = step ? 1 : 0;
59
+ const right = step ? 0 : 1;
60
+ px(c, x - 4, y - 7 + left, 4, 7 - left, outline);
61
+ px(c, x + 1, y - 7 + right, 4, 7 - right, outline);
62
+ px(c, x - 3, y - 6 + left, 2, 5 - left, V.pants);
63
+ px(c, x + 2, y - 6 + right, 2, 5 - right, V.pants);
64
+ px(c, x - 4, y - 1, 4, 2, V.shoes);
65
+ px(c, x + 1, y - 1, 4, 2, V.shoes);
66
+ }
67
+
68
+ px(c, x - 6, y - 17, 12, 11, outline);
69
+ px(c, x - 5, y - 16, 10, 9, p.shirt);
70
+ px(c, x - 5, y - 16, 10, 2, p.trim);
71
+ px(c, x - 4, y - 9, 8, 2, p.trim);
72
+ px(c, x - 4, y - 13, 2, 4, V.shirtShade ?? p.trim);
73
+ px(c, x + 3, y - 15, 1, 5, V.shirtLite ?? p.shirt);
74
+ const armUp = actor.pose === "type" ? (((t / 90) | 0) % 2) : actor.pose === "reach" || actor.pose === "phone" ? 1 : 0;
75
+ if (dir !== "right") {
76
+ px(c, x - 8, y - 16 - armUp, 3, 8, outline);
77
+ px(c, x - 7, y - 15 - armUp, 2, 5, p.shirt);
78
+ px(c, x - 7, y - 10 - armUp, 2, 2, p.skin);
79
+ }
80
+ if (dir !== "left") {
81
+ const other = actor.pose === "type" ? 1 - armUp : armUp;
82
+ px(c, x + 5, y - 16 - other, 3, 8, outline);
83
+ px(c, x + 5, y - 15 - other, 2, 5, p.shirt);
84
+ px(c, x + 5, y - 10 - other, 2, 2, p.skin);
85
+ }
86
+ if (actor.pose === "phone") {
87
+ px(c, x - 2, y - 14, 5, 6, outline);
88
+ px(c, x - 1, y - 13, 3, 4, V.pips.thinking ?? V.faceInk);
89
+ px(c, x, y - 12, 1, 1, V.eyeLite ?? p.skin);
90
+ }
91
+
92
+ px(c, x - 5, y - 27, 10, 11, outline);
93
+ px(c, x - 4, y - 26, 8, 9, p.skin);
94
+ px(c, x - 4, y - 26, 8, 4, p.hair);
95
+ px(c, x - 5, y - 25, 2, 6, p.hair);
96
+ px(c, x + 3, y - 25, 2, 6, p.hair);
97
+ px(c, x - 2, y - 25, 3, 1, V.hairLite ?? p.hair);
98
+ px(c, x - 4, y - 19, 2, 2, skinShade);
99
+ px(c, x + 2, y - 19, 2, 2, skinShade);
100
+ if (dir === "down") {
101
+ px(c, x - 2, y - 21, 1, 2, V.faceInk);
102
+ px(c, x + 1, y - 21, 1, 2, V.faceInk);
103
+ px(c, x - 2, y - 22, 1, 1, V.eyeLite ?? p.skin);
104
+ if (actor.pose === "talk") px(c, x - 1, y - 18, 2, 1, V.mouth);
105
+ } else if (dir === "left") {
106
+ px(c, x - 2, y - 21, 1, 2, V.faceInk);
107
+ px(c, x - 5, y - 26, 5, 7, p.hair);
108
+ } else if (dir === "right") {
109
+ px(c, x + 1, y - 21, 1, 2, V.faceInk);
110
+ px(c, x, y - 26, 5, 7, p.hair);
111
+ } else {
112
+ px(c, x - 5, y - 27, 10, 9, p.hair);
113
+ px(c, x - 2, y - 25, 4, 2, V.hairLite ?? p.hair);
114
+ }
115
+ px(c, x - 1, y - 14, 2, 3, p.badge);
116
+
117
+ const pip = V.pips[actor.state ?? "idle"];
118
+ if (pip) {
119
+ const hidden = actor.state === "thinking" && Math.sin(t / 240) <= -0.2;
120
+ if (!hidden) {
121
+ px(c, x - 2, y - 33, 5, 5, outline);
122
+ px(c, x - 1, y - 32, 3, 3, pip);
123
+ px(c, x, y - 33, 1, 1, pip);
124
+ }
125
+ }
126
+ }
127
+
128
+ function drawCharacter(c, actor, t) {
129
+ if (rich) return drawRichCharacter(c, actor, t);
130
+ const p = actor.palette;
131
+ const walking = actor.pose === "walk";
132
+ const sitting = actor.pose === "sit" || actor.pose === "type";
133
+ const step = walking ? (((actor.walkPhase / 0.16) | 0) % 2) : 0;
134
+ const bob = walking ? (step ? 1 : 0) : Math.sin(t / 620 + actor.seed) > 0.6 ? 1 : 0;
135
+ const y = (actor.y | 0) - (sitting ? 3 : 0) + (sitting ? 0 : bob);
136
+ const x = actor.x | 0;
137
+ const dir = actor.dir ?? "down";
138
+
139
+ px(c, x - 5, y - 1, 10, 2, V.shadow);
140
+ if (!sitting) {
141
+ const leftStep = step ? 1 : 0;
142
+ const rightStep = step ? 0 : 1;
143
+ px(c, x - 3, y - 5 + leftStep, 2, 5 - leftStep, V.pants);
144
+ px(c, x + 1, y - 5 + rightStep, 2, 5 - rightStep, V.pants);
145
+ px(c, x - 3, y - 1, 2, 1, V.shoes);
146
+ px(c, x + 1, y - 1, 2, 1, V.shoes);
147
+ }
148
+
149
+ px(c, x - 4, y - 12, 8, 8, p.shirt);
150
+ px(c, x - 4, y - 12, 8, 1, p.trim);
151
+ px(c, x - 4, y - 6, 8, 2, p.trim);
152
+ const armUp = actor.pose === "type" ? (((t / 90) | 0) % 2) : actor.pose === "reach" ? 1 : 0;
153
+ if (dir === "left") {
154
+ px(c, x - 6, y - 11 - armUp, 2, 5, p.shirt);
155
+ } else if (dir === "right") {
156
+ px(c, x + 4, y - 11 - armUp, 2, 5, p.shirt);
157
+ } else {
158
+ px(c, x - 6, y - 11 - armUp, 2, 5, p.shirt);
159
+ px(c, x + 4, y - 11 - (actor.pose === "type" ? 1 - armUp : armUp), 2, 5, p.shirt);
160
+ }
161
+
162
+ px(c, x - 3, y - 19, 6, 7, p.skin);
163
+ px(c, x - 4, y - 20, 8, 4, p.hair);
164
+ px(c, x - 4, y - 17, 1, 2, p.hair);
165
+ px(c, x + 3, y - 17, 1, 2, p.hair);
166
+ if (dir === "down") {
167
+ px(c, x - 2, y - 16, 1, 2, V.faceInk);
168
+ px(c, x + 1, y - 16, 1, 2, V.faceInk);
169
+ if (actor.pose === "talk") px(c, x - 1, y - 13, 2, 1, V.mouth);
170
+ } else if (dir === "left") {
171
+ px(c, x - 2, y - 16, 1, 2, V.faceInk);
172
+ px(c, x - 4, y - 20, 5, 5, p.hair);
173
+ px(c, x - 3, y - 19, 2, 1, p.skin);
174
+ } else if (dir === "right") {
175
+ px(c, x + 1, y - 16, 1, 2, V.faceInk);
176
+ px(c, x - 1, y - 20, 5, 5, p.hair);
177
+ px(c, x + 1, y - 19, 2, 1, p.skin);
178
+ } else {
179
+ px(c, x - 4, y - 20, 8, 6, p.hair);
180
+ }
181
+ px(c, x - 1, y - 11, 2, 2, p.badge);
182
+
183
+ const pip = V.pips[actor.state ?? "idle"];
184
+ if (pip) {
185
+ const hidden = actor.state === "thinking" && Math.sin(t / 240) <= -0.2;
186
+ if (!hidden) {
187
+ px(c, x - 1, y - 25, 3, 3, pip);
188
+ px(c, x, y - 26, 1, 1, pip);
189
+ }
190
+ }
191
+ }
192
+
193
+ function drawParticle(c, particle) {
194
+ const alpha = Math.max(0, Math.min(1, particle.life / particle.maxLife));
195
+ c.globalAlpha = alpha;
196
+ const x = particle.x | 0;
197
+ const y = particle.y | 0;
198
+ switch (particle.kind) {
199
+ case "key":
200
+ px(c, x, y, 3, 3, V.particles.key);
201
+ px(c, x + 1, y + 1, 1, 1, V.particles.keyInset);
202
+ break;
203
+ case "paper":
204
+ px(c, x - 3, y - 2, 7, 5, V.particles.paper);
205
+ px(c, x - 2, y - 1, 5, 1, V.particles.paperLine);
206
+ px(c, x - 2, y + 1, 3, 1, V.particles.paperLine);
207
+ break;
208
+ case "check":
209
+ px(c, x - 3, y, 2, 2, V.particles.check);
210
+ px(c, x - 1, y + 2, 2, 2, V.particles.check);
211
+ px(c, x + 1, y, 2, 2, V.particles.check);
212
+ px(c, x + 3, y - 2, 2, 2, V.particles.check);
213
+ break;
214
+ case "bang":
215
+ px(c, x, y - 5, 2, 4, V.particles.bang);
216
+ px(c, x, y, 2, 2, V.particles.bang);
217
+ break;
218
+ case "cross":
219
+ px(c, x - 2, y - 2, 2, 2, V.particles.cross);
220
+ px(c, x + 1, y + 1, 2, 2, V.particles.cross);
221
+ px(c, x + 1, y - 2, 2, 2, V.particles.cross);
222
+ px(c, x - 2, y + 1, 2, 2, V.particles.cross);
223
+ break;
224
+ case "spark":
225
+ px(c, x, y, 2, 2, particle.color ?? V.particles.spark);
226
+ break;
227
+ default:
228
+ px(c, x, y, 2, 2, V.particles.fallback);
229
+ }
230
+ c.globalAlpha = 1;
231
+ }
232
+
233
+ return Object.freeze({
234
+ ROLES: skin.roles,
235
+ roleFor,
236
+ paletteFor,
237
+ drawCharacter,
238
+ drawParticle,
239
+ hash,
240
+ content: skin,
241
+ });
242
+ }
@@ -0,0 +1,48 @@
1
+ import { assertManifest } from "./graph-validator.js";
2
+
3
+ /**
4
+ * Preset content refs, in the order the resolved registry reports them.
5
+ * `preset.content` names one file per key, relative to its content directory.
6
+ */
7
+ export const PRESET_CONTENT_SOURCES = Object.freeze({
8
+ style: "styles",
9
+ layout: "layouts",
10
+ agentSkin: "agent-skins",
11
+ props: "props",
12
+ npcs: "npcs",
13
+ lifeActivities: "life-activities",
14
+ atmosphere: "atmospheres",
15
+ environment: "environments",
16
+ });
17
+
18
+ function agentProfileFrom(profileTemplates) {
19
+ const templateId = profileTemplates?.defaultTemplate ?? "builtin/host-agent";
20
+ const template = (profileTemplates?.entries ?? []).find((entry) => entry.id === templateId);
21
+ // Mirrors the Office Spec compiler: the host keeps the identity reported by its
22
+ // adapter, and the Agent Profile template supplies the display defaults.
23
+ return { template: template?.id ?? templateId, appearance: { ...(template?.defaultAppearance ?? {}) } };
24
+ }
25
+
26
+ /**
27
+ * Resolve one Preset Office without a local runtime.
28
+ *
29
+ * Static hosts — the preview server, a published demo — have no Office registry
30
+ * to compile an Office Spec from, so the Preset's own content refs are read
31
+ * directly. The result is the same graph shape `/api/office-content` serves,
32
+ * which is what the validators and the renderers require.
33
+ */
34
+ export async function loadPresetContent(presetId, readJson) {
35
+ const preset = await readJson(`presets/${presetId}.json`);
36
+ assertManifest(preset, "preset");
37
+ const refs = preset.content ?? {};
38
+ const names = Object.keys(PRESET_CONTENT_SOURCES);
39
+ const [loaded, profileTemplates] = await Promise.all([
40
+ Promise.all(names.map((key) => readJson(`${PRESET_CONTENT_SOURCES[key]}/${refs[key]}.json`))),
41
+ readJson("component-library/agent-profile-templates.json"),
42
+ ]);
43
+ const content = Object.fromEntries(names.map((key, index) => [key, loaded[index]]));
44
+ for (const key of names) {
45
+ if (!content[key]) throw new Error(`Preset ${presetId} is missing its ${key} content`);
46
+ }
47
+ return { preset, ...content, agentProfile: agentProfileFrom(profileTemplates) };
48
+ }
@@ -0,0 +1,140 @@
1
+ @import url("/style.css");
2
+
3
+ .dev-controls {
4
+ display: flex;
5
+ align-items: center;
6
+ gap: 8px;
7
+ }
8
+
9
+ .dev-controls[hidden] {
10
+ display: none;
11
+ }
12
+
13
+ .panel-title {
14
+ display: flex;
15
+ align-items: center;
16
+ justify-content: space-between;
17
+ gap: 8px;
18
+ }
19
+
20
+ .panel-title h2 {
21
+ margin: 0;
22
+ }
23
+
24
+ .replay-btn {
25
+ max-width: 190px;
26
+ padding: 6px 10px;
27
+ overflow: hidden;
28
+ color: #17130a;
29
+ background: var(--accent);
30
+ border: 1px solid #ffe59a;
31
+ border-radius: 3px;
32
+ box-shadow: 0 2px 0 #8d6b14;
33
+ font: inherit;
34
+ font-size: 11px;
35
+ font-weight: 800;
36
+ text-overflow: ellipsis;
37
+ white-space: nowrap;
38
+ cursor: pointer;
39
+ }
40
+
41
+ .replay-btn:hover:not(:disabled) {
42
+ filter: brightness(1.08);
43
+ transform: translateY(-1px);
44
+ }
45
+
46
+ .replay-btn:disabled {
47
+ opacity: 0.45;
48
+ cursor: default;
49
+ }
50
+
51
+ .replay-status {
52
+ position: absolute;
53
+ top: 12px;
54
+ left: 50%;
55
+ z-index: 4;
56
+ padding: 7px 12px;
57
+ transform: translateX(-50%);
58
+ color: #17130a;
59
+ background: var(--accent);
60
+ border: 2px solid #fff0b8;
61
+ box-shadow: 0 3px 0 #76570c;
62
+ font-size: 12px;
63
+ font-weight: 800;
64
+ pointer-events: none;
65
+ }
66
+
67
+ .replay-status[hidden] {
68
+ display: none;
69
+ }
70
+
71
+ .client-controls {
72
+ display: grid;
73
+ grid-template-columns: minmax(0, 1fr) auto auto;
74
+ gap: 8px;
75
+ padding: 9px 12px;
76
+ background: var(--panel);
77
+ border-top: 2px solid var(--line);
78
+ }
79
+
80
+ .client-controls .model-select {
81
+ min-width: 0;
82
+ text-overflow: ellipsis;
83
+ }
84
+
85
+ .client-controls[hidden] {
86
+ display: none;
87
+ }
88
+
89
+ .client-controls textarea {
90
+ min-width: 0;
91
+ resize: none;
92
+ padding: 7px 9px;
93
+ background: var(--bg);
94
+ color: var(--ink);
95
+ border: 1px solid var(--line);
96
+ font: inherit;
97
+ font-size: 12px;
98
+ }
99
+
100
+ .client-controls textarea:focus {
101
+ outline: none;
102
+ border-color: var(--accent);
103
+ }
104
+
105
+ .client-controls .primary {
106
+ color: var(--accent);
107
+ }
108
+
109
+ .approval {
110
+ grid-column: 1 / -1;
111
+ display: flex;
112
+ align-items: center;
113
+ gap: 8px;
114
+ padding: 7px 9px;
115
+ background: #211b2c;
116
+ border: 1px solid #594070;
117
+ font-size: 12px;
118
+ }
119
+
120
+ .approval[hidden] {
121
+ display: none;
122
+ }
123
+
124
+ .approval > div {
125
+ min-width: 0;
126
+ flex: 1;
127
+ }
128
+
129
+ .approval strong,
130
+ .approval span {
131
+ display: block;
132
+ }
133
+
134
+ .approval span {
135
+ margin-top: 3px;
136
+ color: var(--dim);
137
+ overflow: hidden;
138
+ text-overflow: ellipsis;
139
+ white-space: nowrap;
140
+ }
@@ -0,0 +1,68 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Agent Live</title>
7
+ <style>
8
+ html.file-mode body { display: grid; place-items: center; padding: 32px; background: #0d1017; color: #d7dee9; font: 14px ui-monospace, monospace; }
9
+ html.file-mode #app { display: none; }
10
+ #fileFallback { display: none; max-width: 520px; padding: 20px; border: 1px solid #2a3243; background: #151a24; }
11
+ html.file-mode #fileFallback { display: block; }
12
+ #fileFallback strong { display: block; margin-bottom: 8px; color: #ffcc4d; font-size: 18px; }
13
+ </style>
14
+ <script>if (location.protocol === "file:") document.documentElement.classList.add("file-mode");</script>
15
+ <link rel="stylesheet" href="/v2/style.css" />
16
+ </head>
17
+ <body>
18
+ <div id="fileFallback"><strong>Agent Live is not running</strong>This is a local source file, not a live office. Run <code>/agent-live</code> in Codex to open a new authenticated session.</div>
19
+ <div id="app">
20
+ <header id="bar">
21
+ <span class="brand">AGENT LIVE</span>
22
+ <span id="conn" class="pill offline" data-i18n="connection.connecting">Connecting…</span>
23
+ <span id="model" class="pill">model: —</span>
24
+ <span id="turns" class="pill">turn 0</span>
25
+ <span id="usage" class="pill">0 tok</span>
26
+ <span class="grow"></span>
27
+ <button id="language" class="btn" type="button" aria-label="Switch language">中文</button>
28
+ <div id="devControls" class="dev-controls" hidden>
29
+ <select id="preset" class="btn" title="Office preset" aria-label="Office preset" data-i18n-title="nav.preset"></select>
30
+ <button id="mute" class="btn">音效: 关</button>
31
+ <button id="demo" class="btn" data-i18n="nav.demo">Demo</button>
32
+ </div>
33
+ </header>
34
+
35
+ <main>
36
+ <div id="stageWrap">
37
+ <canvas id="stage"></canvas>
38
+ <div id="replayStatus" class="replay-status" hidden></div>
39
+ <div id="taskbar"><span class="k" data-i18n="task.label">Current task</span><span id="task" data-i18n="task.empty">Waiting for a task…</span></div>
40
+ </div>
41
+
42
+ <aside id="side">
43
+ <section class="panel">
44
+ <div class="panel-title"><h2 data-i18n="panel.crew">Team</h2><button id="replay" class="replay-btn" type="button" hidden></button></div>
45
+ <div id="crew" class="crew"></div>
46
+ </section>
47
+ <section class="panel grow">
48
+ <h2 data-i18n="panel.activity">Activity</h2>
49
+ <div id="log" class="log"></div>
50
+ </section>
51
+ </aside>
52
+ </main>
53
+
54
+ <form id="clientControls" class="client-controls" hidden>
55
+ <div id="approval" class="approval" hidden>
56
+ <div><strong id="approvalTitle"></strong><span id="approvalDetail"></span></div>
57
+ <button type="button" class="btn" data-approval="deny" data-i18n="approval.deny">Deny</button>
58
+ <button type="button" class="btn" data-approval="allow" data-i18n="approval.allow">Allow</button>
59
+ </div>
60
+ <textarea id="promptInput" rows="2" placeholder="Give Codex a task…" data-i18n-placeholder="client.prompt"></textarea>
61
+ <button id="stopTurn" type="button" class="btn" data-i18n="client.stop">Stop</button>
62
+ <button id="sendPrompt" type="submit" class="btn primary" data-i18n="client.send">Send</button>
63
+ </form>
64
+ </div>
65
+
66
+ <script type="module" src="/v2/bootstrap.js"></script>
67
+ </body>
68
+ </html>