@uemcp/server 1.11.0 → 1.12.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 (3) hide show
  1. package/README.md +34 -1
  2. package/dist/index.mjs +1138 -35
  3. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -384,6 +384,11 @@ const TOOL_METADATA = {
384
384
  add_sequence_binding: mutates("sequence", "add_sequence_binding"),
385
385
  add_sequence_keys: mutates("sequence", "add_sequence_keys"),
386
386
  add_sequence_track: mutates("sequence", "add_sequence_track"),
387
+ add_smart_object_component: idempotentMutates("ai", "add_smart_object_component", [
388
+ "smart object",
389
+ "slot",
390
+ "claim"
391
+ ]),
387
392
  add_state_tree_component: mutates("ai", "add_state_tree_component"),
388
393
  add_state_tree_state: mutates("ai", "add_state_tree_state"),
389
394
  add_stimuli_source: mutates("ai", "add_stimuli_source", [
@@ -489,6 +494,12 @@ const TOOL_METADATA = {
489
494
  create_landscape: mutates("level", "create_landscape"),
490
495
  create_level_sequence: mutates("sequence", "create_level_sequence"),
491
496
  create_material_instance: mutates("fx", "create_material_instance"),
497
+ create_mass_entity_config: mutates("ai", "create_mass_entity_config", [
498
+ "mass",
499
+ "crowd",
500
+ "entity config",
501
+ "trait"
502
+ ]),
492
503
  create_metasound: mutates("audio", "create_metasound"),
493
504
  create_montage: mutates("anim", "create_montage"),
494
505
  create_pcg_graph: mutates("fx", "create_pcg_graph"),
@@ -499,6 +510,11 @@ const TOOL_METADATA = {
499
510
  "cost"
500
511
  ]),
501
512
  create_post_process_volume: mutates("fx", "create_post_process_volume"),
513
+ create_smart_object_definition: mutates("ai", "create_smart_object_definition", [
514
+ "smart object",
515
+ "slot",
516
+ "activity"
517
+ ]),
502
518
  create_sound_cue: mutates("audio", "create_sound_cue"),
503
519
  create_state_tree: mutates("ai", "create_state_tree"),
504
520
  create_struct: mutates("blueprint", "create_struct"),
@@ -512,6 +528,13 @@ const TOOL_METADATA = {
512
528
  delete_asset: destroys("asset", "delete_asset"),
513
529
  delete_data_table: destroys("asset", "delete_data_table"),
514
530
  destroy_actor: destroys("level", "destroy_actor"),
531
+ diagnose_navmesh: readOnly("level", "diagnose_navmesh", [
532
+ "navmesh",
533
+ "navigation",
534
+ "island",
535
+ "spawn",
536
+ "reachable"
537
+ ]),
515
538
  disconnect_pins: mutates("blueprint", "disconnect_pins"),
516
539
  doctor: readOnly("core", void 0, [
517
540
  "diagnose",
@@ -527,6 +550,12 @@ const TOOL_METADATA = {
527
550
  "generator",
528
551
  "score"
529
552
  ]),
553
+ edit_mass_entity_config: mutates("ai", "edit_mass_entity_config", [
554
+ "mass",
555
+ "crowd",
556
+ "entity config",
557
+ "trait"
558
+ ]),
530
559
  enable_toolset: idempotentMutates("core", void 0, [
531
560
  "toolset",
532
561
  "tools",
@@ -620,6 +649,12 @@ const TOOL_METADATA = {
620
649
  get_editor_state: readOnly("core", "get_editor_state"),
621
650
  get_eqs_query: readOnly("ai", "get_eqs_query"),
622
651
  get_import_job_status: readOnly("asset", "get_import_job_status"),
652
+ get_mass_entity_config: readOnly("ai", "get_mass_entity_config", [
653
+ "mass",
654
+ "crowd",
655
+ "entity config",
656
+ "trait"
657
+ ]),
623
658
  get_net_stats: readOnly("test", "get_net_stats", [
624
659
  "network",
625
660
  "multiplayer",
@@ -631,6 +666,7 @@ const TOOL_METADATA = {
631
666
  get_pie_status: readOnly("test", "get_pie_status"),
632
667
  get_project_id: readOnly("core", void 0, ["projectid", "identity"]),
633
668
  get_render_job_status: readOnly("sequence", "get_render_job_status"),
669
+ get_smart_object_definition: readOnly("ai", "get_smart_object_definition", ["smart object", "slot"]),
634
670
  get_source_control_job_status: readOnly("asset", "get_source_control_job_status"),
635
671
  get_source_control_status: readOnly("asset", "get_source_control_status"),
636
672
  get_state_tree: readOnly("ai", "get_state_tree"),
@@ -654,6 +690,12 @@ const TOOL_METADATA = {
654
690
  "enhanced input"
655
691
  ]),
656
692
  launch_on_device: reachesOutside("test", false, "launch_on_device"),
693
+ layout_graph: idempotentMutates("blueprint", "layout_graph", [
694
+ "arrange",
695
+ "tidy",
696
+ "overlap",
697
+ "format"
698
+ ]),
657
699
  link_state_tree_state: mutates("ai", "link_state_tree_state", ["subtree", "linked"]),
658
700
  list_actors: readOnly("core", "list_actors"),
659
701
  list_asset_factories: readOnly("asset", "list_asset_factories"),
@@ -699,6 +741,11 @@ const TOOL_METADATA = {
699
741
  refresh_source_control_status: idempotentMutates("asset", "refresh_source_control_status"),
700
742
  reimport_asset: reachesOutside("asset", false, "reimport_asset"),
701
743
  remove_graph_node: destroys("blueprint", "remove_graph_node"),
744
+ remove_state_tree_elements: destroys("ai", "remove_state_tree_elements", [
745
+ "delete",
746
+ "state",
747
+ "transition"
748
+ ]),
702
749
  rename_asset: mutates("asset", "rename_asset"),
703
750
  rename_data_table: mutates("asset", "rename_data_table"),
704
751
  rename_data_table_row: mutates("asset", "rename_data_table_row"),
@@ -809,6 +856,17 @@ const TOOL_METADATA = {
809
856
  trigger_hot_reload: mutates("build", "start_hot_reload"),
810
857
  trigger_live_compile: mutates("build", "start_live_compile", ["live coding", "recompile"]),
811
858
  undo: mutates("core", "undo"),
859
+ validate_mass_entity_config: readOnly("ai", "validate_mass_entity_config", [
860
+ "mass",
861
+ "crowd",
862
+ "entity config",
863
+ "trait"
864
+ ]),
865
+ update_state_tree_elements: mutates("ai", "update_state_tree_elements", [
866
+ "edit",
867
+ "rename",
868
+ "retarget"
869
+ ]),
812
870
  wait_for_job: readOnly("core", void 0, [
813
871
  "poll",
814
872
  "block",
@@ -1401,6 +1459,10 @@ const bridgeBlueprintNodeSchema = z.object({
1401
1459
  nodeId: z.string(),
1402
1460
  pinCount: z.number().int().min(0),
1403
1461
  pins: z.array(bridgeBlueprintPinSchema),
1462
+ position: z.object({
1463
+ x: z.number().int(),
1464
+ y: z.number().int()
1465
+ }).optional(),
1404
1466
  title: z.string()
1405
1467
  });
1406
1468
  const bridgeErrorResponseSchema = z.object({
@@ -2624,6 +2686,7 @@ const BRIDGE_CONNECT_PINS_REQUEST_TYPE = "connect_pins";
2624
2686
  const BRIDGE_DISCONNECT_PINS_REQUEST_TYPE = "disconnect_pins";
2625
2687
  const BRIDGE_SET_PIN_DEFAULT_REQUEST_TYPE = "set_pin_default";
2626
2688
  const BRIDGE_LIST_AVAILABLE_NODES_REQUEST_TYPE = "list_available_nodes";
2689
+ const BRIDGE_LAYOUT_GRAPH_REQUEST_TYPE = "layout_graph";
2627
2690
  const BRIDGE_GRAPH_PIN_VALUE_MAX_CHARS = 4096;
2628
2691
  const BRIDGE_GRAPH_NODE_POSITION_LIMIT = 1e6;
2629
2692
  const BRIDGE_GRAPH_NODE_KINDS = [
@@ -2641,6 +2704,10 @@ const graphNodePositionSchema = z.object({
2641
2704
  x: z.number().int().min(-1e6).max(BRIDGE_GRAPH_NODE_POSITION_LIMIT).default(0),
2642
2705
  y: z.number().int().min(-1e6).max(BRIDGE_GRAPH_NODE_POSITION_LIMIT).default(0)
2643
2706
  });
2707
+ const graphNodePlacedPositionSchema = z.object({
2708
+ x: z.number().int(),
2709
+ y: z.number().int()
2710
+ });
2644
2711
  const bridgeListGraphNodesRequestSchema = z.object({
2645
2712
  assetPath: assetPathSchema,
2646
2713
  cursor: assetCursorSchema.optional(),
@@ -2653,6 +2720,7 @@ const bridgeListGraphNodesRequestSchema = z.object({
2653
2720
  });
2654
2721
  const bridgeAddGraphNodeRequestFieldsSchema = z.object({
2655
2722
  assetPath: assetPathSchema,
2723
+ autoLayout: z.boolean().optional(),
2656
2724
  graphName: graphNameSchema,
2657
2725
  nodeClass: assetPathSchema.optional(),
2658
2726
  kind: graphNodeKindSchema,
@@ -2704,6 +2772,13 @@ const bridgeSetPinDefaultRequestSchema = z.object({
2704
2772
  value: graphPinValueSchema,
2705
2773
  version: z.literal(2)
2706
2774
  });
2775
+ const bridgeLayoutGraphRequestSchema = z.object({
2776
+ assetPath: assetPathSchema,
2777
+ graphName: graphNameSchema,
2778
+ requestId: requestIdSchema,
2779
+ type: z.literal(BRIDGE_LAYOUT_GRAPH_REQUEST_TYPE),
2780
+ version: z.literal(2)
2781
+ });
2707
2782
  const bridgeListAvailableNodesRequestSchema = z.object({
2708
2783
  assetPath: assetPathSchema,
2709
2784
  cursor: assetCursorSchema.optional(),
@@ -2732,6 +2807,7 @@ const bridgeAddGraphNodeSuccessResponseSchema = z.object({
2732
2807
  message: nonEmptyStringSchema.optional(),
2733
2808
  node: bridgeBlueprintNodeSchema,
2734
2809
  ok: z.literal(true),
2810
+ position: graphNodePlacedPositionSchema.optional(),
2735
2811
  requestId: requestIdSchema,
2736
2812
  state: creativeEditStateSchema,
2737
2813
  type: z.literal(BRIDGE_ADD_GRAPH_NODE_REQUEST_TYPE),
@@ -2807,6 +2883,20 @@ const bridgeListAvailableNodesSuccessResponseSchema = z.object({
2807
2883
  type: z.literal(BRIDGE_LIST_AVAILABLE_NODES_REQUEST_TYPE),
2808
2884
  version: z.literal(2)
2809
2885
  });
2886
+ const bridgeLayoutGraphSuccessResponseSchema = z.object({
2887
+ assetPath: z.string(),
2888
+ graphName: z.string(),
2889
+ layerCount: z.number().int().min(0),
2890
+ message: nonEmptyStringSchema.optional(),
2891
+ movedCount: z.number().int().min(0),
2892
+ nodeCount: z.number().int().min(0),
2893
+ ok: z.literal(true),
2894
+ requestId: requestIdSchema,
2895
+ skippedCount: z.number().int().min(0),
2896
+ state: creativeEditStateSchema,
2897
+ type: z.literal(BRIDGE_LAYOUT_GRAPH_REQUEST_TYPE),
2898
+ version: z.literal(2)
2899
+ });
2810
2900
  const bridgeListGraphNodesResponseSchema = z.union([bridgeListGraphNodesSuccessResponseSchema, bridgeErrorResponseSchema]);
2811
2901
  const bridgeAddGraphNodeResponseSchema = z.union([bridgeAddGraphNodeSuccessResponseSchema, bridgeErrorResponseSchema]);
2812
2902
  const bridgeRemoveGraphNodeResponseSchema = z.union([bridgeRemoveGraphNodeSuccessResponseSchema, bridgeErrorResponseSchema]);
@@ -2814,6 +2904,7 @@ const bridgeConnectPinsResponseSchema = z.union([bridgeConnectPinsSuccessRespons
2814
2904
  const bridgeDisconnectPinsResponseSchema = z.union([bridgeDisconnectPinsSuccessResponseSchema, bridgeErrorResponseSchema]);
2815
2905
  const bridgeSetPinDefaultResponseSchema = z.union([bridgeSetPinDefaultSuccessResponseSchema, bridgeErrorResponseSchema]);
2816
2906
  const bridgeListAvailableNodesResponseSchema = z.union([bridgeListAvailableNodesSuccessResponseSchema, bridgeErrorResponseSchema]);
2907
+ const bridgeLayoutGraphResponseSchema = z.union([bridgeLayoutGraphSuccessResponseSchema, bridgeErrorResponseSchema]);
2817
2908
  function createBridgeListGraphNodesRequest(assetPath, graphName, options = {}, requestId = randomUUID()) {
2818
2909
  return bridgeListGraphNodesRequestSchema.parse({
2819
2910
  assetPath,
@@ -2829,6 +2920,7 @@ function createBridgeListGraphNodesRequest(assetPath, graphName, options = {}, r
2829
2920
  function createBridgeAddGraphNodeRequest(assetPath, graphName, kind, options = {}, requestId = randomUUID()) {
2830
2921
  return bridgeAddGraphNodeRequestSchema.parse({
2831
2922
  assetPath,
2923
+ autoLayout: options.autoLayout,
2832
2924
  graphName,
2833
2925
  kind,
2834
2926
  memberName: options.memberName,
@@ -2901,6 +2993,15 @@ function createBridgeListAvailableNodesRequest(assetPath, graphName, options = {
2901
2993
  version: 2
2902
2994
  });
2903
2995
  }
2996
+ function createBridgeLayoutGraphRequest(assetPath, graphName, requestId = randomUUID()) {
2997
+ return bridgeLayoutGraphRequestSchema.parse({
2998
+ assetPath,
2999
+ graphName,
3000
+ requestId,
3001
+ type: BRIDGE_LAYOUT_GRAPH_REQUEST_TYPE,
3002
+ version: 2
3003
+ });
3004
+ }
2904
3005
  //#endregion
2905
3006
  //#region src/protocol/debugger.ts
2906
3007
  const BRIDGE_SET_BLUEPRINT_BREAKPOINT_REQUEST_TYPE = "set_blueprint_breakpoint";
@@ -7441,6 +7542,7 @@ const bridgeStateTreeNodeReportSchema = z.object({
7441
7542
  const bridgeStateTreeTransitionReportSchema = z.object({
7442
7543
  eventTag: z.string().optional(),
7443
7544
  id: z.string(),
7545
+ targetStateId: z.string().optional(),
7444
7546
  targetStateName: z.string().optional(),
7445
7547
  targetType: z.string(),
7446
7548
  trigger: z.string()
@@ -7688,6 +7790,141 @@ function createBridgeTraceStateTreeRequest(action, options = {}, requestId = ran
7688
7790
  version: 2
7689
7791
  });
7690
7792
  }
7793
+ const BRIDGE_UPDATE_STATE_TREE_ELEMENTS_REQUEST_TYPE = "update_state_tree_elements";
7794
+ const BRIDGE_REMOVE_STATE_TREE_ELEMENTS_REQUEST_TYPE = "remove_state_tree_elements";
7795
+ const BRIDGE_STATE_TREE_ELEMENT_KINDS = [
7796
+ "state",
7797
+ "task",
7798
+ "transition"
7799
+ ];
7800
+ const BRIDGE_STATE_TREE_EDITABLE_STATE_TYPES = [
7801
+ "state",
7802
+ "group",
7803
+ "subtree"
7804
+ ];
7805
+ const BRIDGE_STATE_TREE_TRANSITION_TARGET_TYPES = [
7806
+ "none",
7807
+ "succeeded",
7808
+ "failed",
7809
+ "next_state",
7810
+ "goto_state"
7811
+ ];
7812
+ const stateTreeElementIdSchema = z.string().trim().regex(/^[{(]?[0-9A-Fa-f]{8}-?[0-9A-Fa-f]{4}-?[0-9A-Fa-f]{4}-?[0-9A-Fa-f]{4}-?[0-9A-Fa-f]{12}[)}]?$/);
7813
+ const stateTreeElementKindSchema = z.enum(BRIDGE_STATE_TREE_ELEMENT_KINDS);
7814
+ const stateTreeEditableStateTypeSchema = z.enum(BRIDGE_STATE_TREE_EDITABLE_STATE_TYPES);
7815
+ const stateTreeTransitionTargetTypeSchema = z.enum(BRIDGE_STATE_TREE_TRANSITION_TARGET_TYPES);
7816
+ const stateTreeEditableTriggerSchema = z.enum(BRIDGE_STATE_TREE_TRANSITION_TRIGGERS);
7817
+ const bridgeStateTreeElementUpdateSchema = z.discriminatedUnion("kind", [
7818
+ z.object({
7819
+ enabled: z.boolean().optional(),
7820
+ id: stateTreeElementIdSchema,
7821
+ kind: z.literal("state"),
7822
+ name: userTypeIdentifierSchema.optional(),
7823
+ selectionBehavior: stateTreeSelectionBehaviorSchema.optional(),
7824
+ stateType: stateTreeEditableStateTypeSchema.optional()
7825
+ }),
7826
+ z.object({
7827
+ id: stateTreeElementIdSchema,
7828
+ kind: z.literal("task"),
7829
+ params: eqsParamsSchema
7830
+ }),
7831
+ z.object({
7832
+ enabled: z.boolean().optional(),
7833
+ eventTag: boundedStringSchema.optional(),
7834
+ id: stateTreeElementIdSchema,
7835
+ kind: z.literal("transition"),
7836
+ targetStateId: stateTreeElementIdSchema.optional(),
7837
+ targetType: stateTreeTransitionTargetTypeSchema.optional(),
7838
+ trigger: stateTreeEditableTriggerSchema.optional()
7839
+ })
7840
+ ]).superRefine((update, ctx) => {
7841
+ if (update.kind === "task") {
7842
+ if (Object.keys(update.params).length === 0) ctx.addIssue({
7843
+ code: z.ZodIssueCode.custom,
7844
+ message: "A task update must set at least one param.",
7845
+ path: ["params"]
7846
+ });
7847
+ return;
7848
+ }
7849
+ const { id: _id, kind: _kind, ...fields } = update;
7850
+ if (Object.values(fields).every((value) => value === void 0)) ctx.addIssue({
7851
+ code: z.ZodIssueCode.custom,
7852
+ message: `A ${update.kind} update must change at least one field.`
7853
+ });
7854
+ if (update.kind !== "transition") return;
7855
+ if (update.targetType === "goto_state" && update.targetStateId === void 0) ctx.addIssue({
7856
+ code: z.ZodIssueCode.custom,
7857
+ message: "A 'goto_state' transition must name its targetStateId.",
7858
+ path: ["targetStateId"]
7859
+ });
7860
+ if (update.targetStateId !== void 0 && update.targetType !== void 0 && update.targetType !== "goto_state") ctx.addIssue({
7861
+ code: z.ZodIssueCode.custom,
7862
+ message: "Only a 'goto_state' transition names a targetStateId.",
7863
+ path: ["targetStateId"]
7864
+ });
7865
+ });
7866
+ const bridgeUpdateStateTreeElementsRequestSchema = z.object({
7867
+ assetPath: assetPathSchema,
7868
+ compile: z.boolean().default(true),
7869
+ requestId: requestIdSchema,
7870
+ type: z.literal(BRIDGE_UPDATE_STATE_TREE_ELEMENTS_REQUEST_TYPE),
7871
+ updates: z.array(bridgeStateTreeElementUpdateSchema).min(1).max(32),
7872
+ version: z.literal(2)
7873
+ });
7874
+ const bridgeUpdateStateTreeElementsSuccessResponseSchema = z.object({
7875
+ ...authoringBatchResponseFields,
7876
+ compileMessages: z.array(z.string()).max(25),
7877
+ compiled: z.boolean(),
7878
+ type: z.literal(BRIDGE_UPDATE_STATE_TREE_ELEMENTS_REQUEST_TYPE)
7879
+ });
7880
+ const bridgeStateTreeElementRemovalSchema = z.object({
7881
+ id: stateTreeElementIdSchema,
7882
+ kind: stateTreeElementKindSchema
7883
+ });
7884
+ const bridgeRemoveStateTreeElementsRequestSchema = z.object({
7885
+ assetPath: assetPathSchema,
7886
+ compile: z.boolean().default(true),
7887
+ removals: z.array(bridgeStateTreeElementRemovalSchema).min(1).max(32),
7888
+ requestId: requestIdSchema,
7889
+ type: z.literal(BRIDGE_REMOVE_STATE_TREE_ELEMENTS_REQUEST_TYPE),
7890
+ version: z.literal(2)
7891
+ });
7892
+ const bridgeStateTreeRemovedTransitionSchema = z.object({
7893
+ id: z.string(),
7894
+ ownerStateId: z.string(),
7895
+ ownerStateName: z.string(),
7896
+ targetStateName: z.string()
7897
+ });
7898
+ const bridgeRemoveStateTreeElementsSuccessResponseSchema = z.object({
7899
+ ...authoringBatchResponseFields,
7900
+ compileMessages: z.array(z.string()).max(25),
7901
+ compiled: z.boolean(),
7902
+ removedTransitionCount: z.number().int().min(0),
7903
+ removedTransitions: z.array(bridgeStateTreeRemovedTransitionSchema).max(128),
7904
+ type: z.literal(BRIDGE_REMOVE_STATE_TREE_ELEMENTS_REQUEST_TYPE)
7905
+ });
7906
+ const bridgeUpdateStateTreeElementsResponseSchema = z.union([bridgeUpdateStateTreeElementsSuccessResponseSchema, bridgeErrorResponseSchema]);
7907
+ const bridgeRemoveStateTreeElementsResponseSchema = z.union([bridgeRemoveStateTreeElementsSuccessResponseSchema, bridgeErrorResponseSchema]);
7908
+ function createBridgeUpdateStateTreeElementsRequest(assetPath, updates, options = {}, requestId = randomUUID()) {
7909
+ return bridgeUpdateStateTreeElementsRequestSchema.parse({
7910
+ assetPath,
7911
+ compile: options.compile,
7912
+ requestId,
7913
+ type: BRIDGE_UPDATE_STATE_TREE_ELEMENTS_REQUEST_TYPE,
7914
+ updates,
7915
+ version: 2
7916
+ });
7917
+ }
7918
+ function createBridgeRemoveStateTreeElementsRequest(assetPath, removals, options = {}, requestId = randomUUID()) {
7919
+ return bridgeRemoveStateTreeElementsRequestSchema.parse({
7920
+ assetPath,
7921
+ compile: options.compile,
7922
+ removals,
7923
+ requestId,
7924
+ type: BRIDGE_REMOVE_STATE_TREE_ELEMENTS_REQUEST_TYPE,
7925
+ version: 2
7926
+ });
7927
+ }
7691
7928
  //#endregion
7692
7929
  //#region src/protocol/perception.ts
7693
7930
  const BRIDGE_CREATE_AI_CONTROLLER_REQUEST_TYPE = "create_ai_controller";
@@ -11015,9 +11252,366 @@ function createBridgeTestReachabilityRequest(pairs, options = {}, requestId = ra
11015
11252
  version: 2
11016
11253
  });
11017
11254
  }
11255
+ const BRIDGE_DIAGNOSE_NAVMESH_REQUEST_TYPE = "diagnose_navmesh";
11256
+ const BRIDGE_NAV_DIAGNOSTIC_ISSUE_CODES = [
11257
+ "missing_nav_bounds",
11258
+ "nav_bounds_empty",
11259
+ "no_navigation_data",
11260
+ "navmesh_empty",
11261
+ "no_spawn_points",
11262
+ "island_without_spawn",
11263
+ "spawn_not_found",
11264
+ "spawn_off_navmesh",
11265
+ "spawn_unreachable"
11266
+ ];
11267
+ const BRIDGE_NAV_SPAWN_POINT_KINDS = ["player_start", "actor"];
11268
+ const bridgeDiagnoseNavmeshRequestSchema = z.object({
11269
+ includePlayerStarts: z.boolean().default(true),
11270
+ maxIslands: z.number().int().min(1).max(64).default(16),
11271
+ navMeshActorPath: actorPathSchema.optional(),
11272
+ requestId: requestIdSchema,
11273
+ spawnActorPaths: z.array(actorPathSchema).max(64).default([]),
11274
+ type: z.literal(BRIDGE_DIAGNOSE_NAVMESH_REQUEST_TYPE),
11275
+ version: z.literal(2)
11276
+ });
11277
+ const navDiagnosticIslandSchema = z.object({
11278
+ area: z.number().min(0),
11279
+ bounds: z.object({
11280
+ max: navPointSchema,
11281
+ min: navPointSchema
11282
+ }),
11283
+ index: z.number().int().min(0),
11284
+ polyCount: z.number().int().min(0),
11285
+ spawnPointCount: z.number().int().min(0)
11286
+ });
11287
+ const navDiagnosticSpawnPointSchema = z.object({
11288
+ actorPath: z.string(),
11289
+ error: z.string().optional(),
11290
+ islandIndex: z.number().int().min(0).optional(),
11291
+ kind: z.enum(BRIDGE_NAV_SPAWN_POINT_KINDS),
11292
+ location: navPointSchema,
11293
+ onNavMesh: z.boolean(),
11294
+ pathLength: z.number().optional(),
11295
+ projectedLocation: navPointSchema.optional(),
11296
+ reachableFromAnchor: z.boolean()
11297
+ });
11298
+ const navDiagnosticIssueSchema = z.object({
11299
+ actorPath: z.string().optional(),
11300
+ code: z.enum(BRIDGE_NAV_DIAGNOSTIC_ISSUE_CODES),
11301
+ islandIndex: z.number().int().min(0).optional(),
11302
+ message: z.string()
11303
+ });
11304
+ const bridgeDiagnoseNavmeshSuccessResponseSchema = z.object({
11305
+ anchorActorPath: z.string().optional(),
11306
+ healthy: z.boolean(),
11307
+ islandCount: z.number().int().min(0),
11308
+ islands: z.array(navDiagnosticIslandSchema).max(64),
11309
+ islandsTruncated: z.boolean(),
11310
+ issueCount: z.number().int().min(0),
11311
+ issues: z.array(navDiagnosticIssueSchema).max(64),
11312
+ issuesTruncated: z.boolean(),
11313
+ message: nonEmptyStringSchema.optional(),
11314
+ navBoundsVolumeCount: z.number().int().min(0),
11315
+ navMeshActorPath: z.string(),
11316
+ ok: z.literal(true),
11317
+ polyCount: z.number().int().min(0),
11318
+ requestId: requestIdSchema,
11319
+ spawnPointCount: z.number().int().min(0),
11320
+ spawnPoints: z.array(navDiagnosticSpawnPointSchema).max(64),
11321
+ spawnPointsTruncated: z.boolean(),
11322
+ state: navQueryStateSchema,
11323
+ type: z.literal(BRIDGE_DIAGNOSE_NAVMESH_REQUEST_TYPE),
11324
+ version: z.literal(2)
11325
+ });
11326
+ const bridgeDiagnoseNavmeshResponseSchema = z.union([bridgeDiagnoseNavmeshSuccessResponseSchema, bridgeErrorResponseSchema]);
11327
+ function createBridgeDiagnoseNavmeshRequest(options = {}, requestId = randomUUID()) {
11328
+ return bridgeDiagnoseNavmeshRequestSchema.parse({
11329
+ includePlayerStarts: options.includePlayerStarts,
11330
+ maxIslands: options.maxIslands,
11331
+ navMeshActorPath: options.navMeshActorPath,
11332
+ requestId,
11333
+ spawnActorPaths: options.spawnActorPaths,
11334
+ type: BRIDGE_DIAGNOSE_NAVMESH_REQUEST_TYPE,
11335
+ version: 2
11336
+ });
11337
+ }
11338
+ //#endregion
11339
+ //#region src/protocol/smartObjects.ts
11340
+ const BRIDGE_CREATE_SMART_OBJECT_DEFINITION_REQUEST_TYPE = "create_smart_object_definition";
11341
+ const BRIDGE_GET_SMART_OBJECT_DEFINITION_REQUEST_TYPE = "get_smart_object_definition";
11342
+ const BRIDGE_ADD_SMART_OBJECT_COMPONENT_REQUEST_TYPE = "add_smart_object_component";
11343
+ const BRIDGE_SMART_OBJECT_COMPONENT_TARGETS = ["blueprint", "actor"];
11344
+ const bridgeSmartObjectBehaviorDefinitionSchema = z.object({
11345
+ behaviorClass: assetPathSchema,
11346
+ params: instancedObjectParamsSchema
11347
+ });
11348
+ const activityTagsSchema = z.array(gameplayTagNameSchema).max(16).default([]);
11349
+ const behaviorDefinitionsSchema = z.array(bridgeSmartObjectBehaviorDefinitionSchema).max(8).default([]);
11350
+ const bridgeSmartObjectSlotSchema = z.object({
11351
+ activityTags: activityTagsSchema,
11352
+ behaviorDefinitions: behaviorDefinitionsSchema,
11353
+ enabled: z.boolean().default(true),
11354
+ name: requiredBoundedStringSchema.optional(),
11355
+ offset: bridgeVectorSchema.optional(),
11356
+ rotation: bridgeRotatorSchema.optional()
11357
+ });
11358
+ const bridgeCreateSmartObjectDefinitionRequestSchema = z.object({
11359
+ activityTags: activityTagsSchema,
11360
+ assetName: assetNameSchema,
11361
+ defaultBehaviorDefinitions: behaviorDefinitionsSchema,
11362
+ packagePath: contentPathSchema,
11363
+ requestId: requestIdSchema,
11364
+ slots: z.array(bridgeSmartObjectSlotSchema).min(1).max(32),
11365
+ type: z.literal(BRIDGE_CREATE_SMART_OBJECT_DEFINITION_REQUEST_TYPE),
11366
+ version: z.literal(2)
11367
+ });
11368
+ const bridgeGetSmartObjectDefinitionRequestSchema = z.object({
11369
+ assetPath: assetPathSchema,
11370
+ requestId: requestIdSchema,
11371
+ type: z.literal(BRIDGE_GET_SMART_OBJECT_DEFINITION_REQUEST_TYPE),
11372
+ version: z.literal(2)
11373
+ });
11374
+ const bridgeAddSmartObjectComponentRequestFieldsSchema = z.object({
11375
+ actorPath: actorPathSchema.optional(),
11376
+ blueprintPath: assetPathSchema.optional(),
11377
+ componentName: requiredBoundedStringSchema.optional(),
11378
+ definitionPath: assetPathSchema,
11379
+ requestId: requestIdSchema,
11380
+ type: z.literal(BRIDGE_ADD_SMART_OBJECT_COMPONENT_REQUEST_TYPE),
11381
+ version: z.literal(2)
11382
+ });
11383
+ const bridgeAddSmartObjectComponentRequestSchema = bridgeAddSmartObjectComponentRequestFieldsSchema.refine((request) => request.actorPath === void 0 !== (request.blueprintPath === void 0), {
11384
+ message: "An add_smart_object_component request names exactly one of blueprintPath or actorPath.",
11385
+ path: ["blueprintPath"]
11386
+ });
11387
+ const bridgeSmartObjectSlotReportSchema = z.object({
11388
+ activityTags: z.array(z.string()).max(16),
11389
+ behaviorDefinitions: z.array(z.string()).max(8),
11390
+ enabled: z.boolean(),
11391
+ index: z.number().int().min(0),
11392
+ name: z.string(),
11393
+ offset: bridgeVectorSchema,
11394
+ rotation: bridgeRotatorSchema
11395
+ });
11396
+ const smartObjectDefinitionReportFields = {
11397
+ activityTags: z.array(z.string()).max(16),
11398
+ defaultBehaviorDefinitions: z.array(z.string()).max(8),
11399
+ slots: z.array(bridgeSmartObjectSlotReportSchema).max(32),
11400
+ valid: z.boolean(),
11401
+ validationMessages: z.array(z.string()).max(32)
11402
+ };
11403
+ const bridgeCreateSmartObjectDefinitionSuccessResponseSchema = z.object({
11404
+ ...createdUserAssetResponseFields,
11405
+ ...smartObjectDefinitionReportFields,
11406
+ type: z.literal(BRIDGE_CREATE_SMART_OBJECT_DEFINITION_REQUEST_TYPE)
11407
+ });
11408
+ const bridgeGetSmartObjectDefinitionSuccessResponseSchema = z.object({
11409
+ ...smartObjectDefinitionReportFields,
11410
+ assetPath: z.string(),
11411
+ message: nonEmptyStringSchema.optional(),
11412
+ ok: z.literal(true),
11413
+ requestId: requestIdSchema,
11414
+ state: aiReportStateSchema,
11415
+ type: z.literal(BRIDGE_GET_SMART_OBJECT_DEFINITION_REQUEST_TYPE),
11416
+ version: z.literal(2)
11417
+ });
11418
+ const bridgeAddSmartObjectComponentSuccessResponseSchema = z.object({
11419
+ componentName: z.string(),
11420
+ created: z.boolean(),
11421
+ definitionPath: z.string(),
11422
+ definitionValid: z.boolean(),
11423
+ message: nonEmptyStringSchema.optional(),
11424
+ ok: z.literal(true),
11425
+ packageDirty: z.boolean(),
11426
+ requestId: requestIdSchema,
11427
+ state: creativeEditStateSchema,
11428
+ target: z.enum(BRIDGE_SMART_OBJECT_COMPONENT_TARGETS),
11429
+ targetPath: z.string(),
11430
+ type: z.literal(BRIDGE_ADD_SMART_OBJECT_COMPONENT_REQUEST_TYPE),
11431
+ version: z.literal(2)
11432
+ });
11433
+ const bridgeCreateSmartObjectDefinitionResponseSchema = z.union([bridgeCreateSmartObjectDefinitionSuccessResponseSchema, bridgeErrorResponseSchema]);
11434
+ const bridgeGetSmartObjectDefinitionResponseSchema = z.union([bridgeGetSmartObjectDefinitionSuccessResponseSchema, bridgeErrorResponseSchema]);
11435
+ const bridgeAddSmartObjectComponentResponseSchema = z.union([bridgeAddSmartObjectComponentSuccessResponseSchema, bridgeErrorResponseSchema]);
11436
+ function createBridgeCreateSmartObjectDefinitionRequest(assetName, packagePath, slots, options = {}, requestId = randomUUID()) {
11437
+ return bridgeCreateSmartObjectDefinitionRequestSchema.parse({
11438
+ activityTags: options.activityTags,
11439
+ assetName,
11440
+ defaultBehaviorDefinitions: options.defaultBehaviorDefinitions,
11441
+ packagePath,
11442
+ requestId,
11443
+ slots,
11444
+ type: BRIDGE_CREATE_SMART_OBJECT_DEFINITION_REQUEST_TYPE,
11445
+ version: 2
11446
+ });
11447
+ }
11448
+ function createBridgeGetSmartObjectDefinitionRequest(assetPath, requestId = randomUUID()) {
11449
+ return bridgeGetSmartObjectDefinitionRequestSchema.parse({
11450
+ assetPath,
11451
+ requestId,
11452
+ type: BRIDGE_GET_SMART_OBJECT_DEFINITION_REQUEST_TYPE,
11453
+ version: 2
11454
+ });
11455
+ }
11456
+ function createBridgeAddSmartObjectComponentRequest(definitionPath, target, options = {}, requestId = randomUUID()) {
11457
+ return bridgeAddSmartObjectComponentRequestSchema.parse({
11458
+ actorPath: target.actorPath,
11459
+ blueprintPath: target.blueprintPath,
11460
+ componentName: options.componentName,
11461
+ definitionPath,
11462
+ requestId,
11463
+ type: BRIDGE_ADD_SMART_OBJECT_COMPONENT_REQUEST_TYPE,
11464
+ version: 2
11465
+ });
11466
+ }
11467
+ //#endregion
11468
+ //#region src/protocol/mass.ts
11469
+ const BRIDGE_CREATE_MASS_ENTITY_CONFIG_REQUEST_TYPE = "create_mass_entity_config";
11470
+ const BRIDGE_EDIT_MASS_ENTITY_CONFIG_REQUEST_TYPE = "edit_mass_entity_config";
11471
+ const BRIDGE_GET_MASS_ENTITY_CONFIG_REQUEST_TYPE = "get_mass_entity_config";
11472
+ const BRIDGE_VALIDATE_MASS_ENTITY_CONFIG_REQUEST_TYPE = "validate_mass_entity_config";
11473
+ const BRIDGE_MASS_TRAIT_OPERATIONS = [
11474
+ "add",
11475
+ "remove",
11476
+ "set"
11477
+ ];
11478
+ const BRIDGE_MASS_READ_STATES = ["reported", "unsupported"];
11479
+ const BRIDGE_MASS_VALIDATION_SEVERITIES = ["error", "warning"];
11480
+ const massReadStateSchema = z.enum(BRIDGE_MASS_READ_STATES);
11481
+ const traitClassSchema = z.string().trim().min(1).max(512);
11482
+ const bridgeMassTraitEditSchema = z.object({
11483
+ operation: z.enum(BRIDGE_MASS_TRAIT_OPERATIONS),
11484
+ properties: z.array(bridgeAssetPropertyEntrySchema).max(32).optional(),
11485
+ traitClass: traitClassSchema
11486
+ }).superRefine((edit, context) => {
11487
+ const count = edit.properties?.length ?? 0;
11488
+ if (edit.operation === "set" && count === 0) context.addIssue({
11489
+ code: z.ZodIssueCode.custom,
11490
+ message: "A 'set' trait edit must carry at least one property.",
11491
+ path: ["properties"]
11492
+ });
11493
+ if (edit.operation === "remove" && count > 0) context.addIssue({
11494
+ code: z.ZodIssueCode.custom,
11495
+ message: "A 'remove' trait edit cannot carry properties.",
11496
+ path: ["properties"]
11497
+ });
11498
+ });
11499
+ const bridgeCreateMassEntityConfigRequestSchema = z.object({
11500
+ assetName: assetNameSchema,
11501
+ packagePath: contentPathSchema,
11502
+ parentConfigPath: assetPathSchema.optional(),
11503
+ requestId: requestIdSchema,
11504
+ type: z.literal(BRIDGE_CREATE_MASS_ENTITY_CONFIG_REQUEST_TYPE),
11505
+ version: z.literal(2)
11506
+ });
11507
+ const bridgeEditMassEntityConfigRequestSchema = z.object({
11508
+ assetPath: assetPathSchema,
11509
+ edits: z.array(bridgeMassTraitEditSchema).min(1).max(16),
11510
+ requestId: requestIdSchema,
11511
+ type: z.literal(BRIDGE_EDIT_MASS_ENTITY_CONFIG_REQUEST_TYPE),
11512
+ version: z.literal(2)
11513
+ });
11514
+ const bridgeGetMassEntityConfigRequestSchema = z.object({
11515
+ assetPath: assetPathSchema,
11516
+ requestId: requestIdSchema,
11517
+ type: z.literal(BRIDGE_GET_MASS_ENTITY_CONFIG_REQUEST_TYPE),
11518
+ version: z.literal(2)
11519
+ });
11520
+ const bridgeValidateMassEntityConfigRequestSchema = z.object({
11521
+ assetPath: assetPathSchema,
11522
+ requestId: requestIdSchema,
11523
+ type: z.literal(BRIDGE_VALIDATE_MASS_ENTITY_CONFIG_REQUEST_TYPE),
11524
+ version: z.literal(2)
11525
+ });
11526
+ const bridgeCreateMassEntityConfigSuccessResponseSchema = z.object({
11527
+ ...createdUserAssetResponseFields,
11528
+ parentConfigPath: z.string().optional(),
11529
+ type: z.literal(BRIDGE_CREATE_MASS_ENTITY_CONFIG_REQUEST_TYPE)
11530
+ });
11531
+ const bridgeEditMassEntityConfigSuccessResponseSchema = z.object({
11532
+ ...authoringBatchResponseFields,
11533
+ traits: z.array(z.string()).max(64),
11534
+ type: z.literal(BRIDGE_EDIT_MASS_ENTITY_CONFIG_REQUEST_TYPE)
11535
+ });
11536
+ const bridgeMassTraitReportSchema = z.object({
11537
+ index: z.number().int().min(0),
11538
+ properties: z.record(z.string(), z.string()),
11539
+ traitClass: z.string(),
11540
+ traitName: z.string()
11541
+ });
11542
+ const bridgeGetMassEntityConfigSuccessResponseSchema = z.object({
11543
+ assetPath: z.string(),
11544
+ message: nonEmptyStringSchema.optional(),
11545
+ ok: z.literal(true),
11546
+ parentConfigPath: z.string().optional(),
11547
+ requestId: requestIdSchema,
11548
+ state: massReadStateSchema,
11549
+ traits: z.array(bridgeMassTraitReportSchema).max(64),
11550
+ truncated: z.boolean(),
11551
+ type: z.literal(BRIDGE_GET_MASS_ENTITY_CONFIG_REQUEST_TYPE),
11552
+ version: z.literal(2)
11553
+ });
11554
+ const bridgeMassValidationMessageSchema = z.object({
11555
+ category: z.string(),
11556
+ severity: z.enum(BRIDGE_MASS_VALIDATION_SEVERITIES),
11557
+ text: z.string()
11558
+ });
11559
+ const bridgeValidateMassEntityConfigSuccessResponseSchema = z.object({
11560
+ assetPath: z.string(),
11561
+ errorCount: z.number().int().min(0),
11562
+ message: nonEmptyStringSchema.optional(),
11563
+ messages: z.array(bridgeMassValidationMessageSchema).max(32),
11564
+ ok: z.literal(true),
11565
+ requestId: requestIdSchema,
11566
+ state: massReadStateSchema,
11567
+ truncated: z.boolean(),
11568
+ type: z.literal(BRIDGE_VALIDATE_MASS_ENTITY_CONFIG_REQUEST_TYPE),
11569
+ valid: z.boolean(),
11570
+ version: z.literal(2),
11571
+ warningCount: z.number().int().min(0)
11572
+ });
11573
+ const bridgeCreateMassEntityConfigResponseSchema = z.union([bridgeCreateMassEntityConfigSuccessResponseSchema, bridgeErrorResponseSchema]);
11574
+ const bridgeEditMassEntityConfigResponseSchema = z.union([bridgeEditMassEntityConfigSuccessResponseSchema, bridgeErrorResponseSchema]);
11575
+ const bridgeGetMassEntityConfigResponseSchema = z.union([bridgeGetMassEntityConfigSuccessResponseSchema, bridgeErrorResponseSchema]);
11576
+ const bridgeValidateMassEntityConfigResponseSchema = z.union([bridgeValidateMassEntityConfigSuccessResponseSchema, bridgeErrorResponseSchema]);
11577
+ function createBridgeCreateMassEntityConfigRequest(assetName, packagePath, options = {}, requestId = randomUUID()) {
11578
+ return bridgeCreateMassEntityConfigRequestSchema.parse({
11579
+ assetName,
11580
+ packagePath,
11581
+ parentConfigPath: options.parentConfigPath,
11582
+ requestId,
11583
+ type: BRIDGE_CREATE_MASS_ENTITY_CONFIG_REQUEST_TYPE,
11584
+ version: 2
11585
+ });
11586
+ }
11587
+ function createBridgeEditMassEntityConfigRequest(assetPath, edits, requestId = randomUUID()) {
11588
+ return bridgeEditMassEntityConfigRequestSchema.parse({
11589
+ assetPath,
11590
+ edits,
11591
+ requestId,
11592
+ type: BRIDGE_EDIT_MASS_ENTITY_CONFIG_REQUEST_TYPE,
11593
+ version: 2
11594
+ });
11595
+ }
11596
+ function createBridgeGetMassEntityConfigRequest(assetPath, requestId = randomUUID()) {
11597
+ return bridgeGetMassEntityConfigRequestSchema.parse({
11598
+ assetPath,
11599
+ requestId,
11600
+ type: BRIDGE_GET_MASS_ENTITY_CONFIG_REQUEST_TYPE,
11601
+ version: 2
11602
+ });
11603
+ }
11604
+ function createBridgeValidateMassEntityConfigRequest(assetPath, requestId = randomUUID()) {
11605
+ return bridgeValidateMassEntityConfigRequestSchema.parse({
11606
+ assetPath,
11607
+ requestId,
11608
+ type: BRIDGE_VALIDATE_MASS_ENTITY_CONFIG_REQUEST_TYPE,
11609
+ version: 2
11610
+ });
11611
+ }
11018
11612
  //#endregion
11019
11613
  //#region src/version.ts
11020
- const SERVER_VERSION = "1.11.0";
11614
+ const SERVER_VERSION = "1.12.0";
11021
11615
  //#endregion
11022
11616
  //#region src/bridgeSocketClient.ts
11023
11617
  var BridgeSocketError = class extends Error {
@@ -11253,6 +11847,9 @@ async function sendBridgeSetPinDefaultRequest(request, options) {
11253
11847
  async function sendBridgeListAvailableNodesRequest(request, options) {
11254
11848
  return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeListAvailableNodesResponseSchema, request.requestId);
11255
11849
  }
11850
+ async function sendBridgeLayoutGraphRequest(request, options) {
11851
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeLayoutGraphResponseSchema, request.requestId);
11852
+ }
11256
11853
  async function sendBridgeSetViewportCameraRequest(request, options) {
11257
11854
  return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeSetViewportCameraResponseSchema, request.requestId);
11258
11855
  }
@@ -11973,6 +12570,36 @@ async function sendBridgeFindPathRequest(request, options) {
11973
12570
  async function sendBridgeTestReachabilityRequest(request, options) {
11974
12571
  return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeTestReachabilityResponseSchema, request.requestId);
11975
12572
  }
12573
+ async function sendBridgeCreateSmartObjectDefinitionRequest(request, options) {
12574
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeCreateSmartObjectDefinitionResponseSchema, request.requestId);
12575
+ }
12576
+ async function sendBridgeGetSmartObjectDefinitionRequest(request, options) {
12577
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeGetSmartObjectDefinitionResponseSchema, request.requestId);
12578
+ }
12579
+ async function sendBridgeAddSmartObjectComponentRequest(request, options) {
12580
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeAddSmartObjectComponentResponseSchema, request.requestId);
12581
+ }
12582
+ async function sendBridgeCreateMassEntityConfigRequest(request, options) {
12583
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeCreateMassEntityConfigResponseSchema, request.requestId);
12584
+ }
12585
+ async function sendBridgeEditMassEntityConfigRequest(request, options) {
12586
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeEditMassEntityConfigResponseSchema, request.requestId);
12587
+ }
12588
+ async function sendBridgeGetMassEntityConfigRequest(request, options) {
12589
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeGetMassEntityConfigResponseSchema, request.requestId);
12590
+ }
12591
+ async function sendBridgeValidateMassEntityConfigRequest(request, options) {
12592
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeValidateMassEntityConfigResponseSchema, request.requestId);
12593
+ }
12594
+ async function sendBridgeDiagnoseNavmeshRequest(request, options) {
12595
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeDiagnoseNavmeshResponseSchema, request.requestId);
12596
+ }
12597
+ async function sendBridgeUpdateStateTreeElementsRequest(request, options) {
12598
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeUpdateStateTreeElementsResponseSchema, request.requestId);
12599
+ }
12600
+ async function sendBridgeRemoveStateTreeElementsRequest(request, options) {
12601
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeRemoveStateTreeElementsResponseSchema, request.requestId);
12602
+ }
11976
12603
  //#endregion
11977
12604
  //#region src/enginePing.ts
11978
12605
  async function pingRegistryEntry$1(entry, options) {
@@ -18799,6 +19426,7 @@ const debuggerToolDomain = {
18799
19426
  };
18800
19427
  //#endregion
18801
19428
  //#region src/traceAnalysis.ts
19429
+ const LLM_TAG_COUNTER_PATTERN = "STAT_*LLM";
18802
19430
  const SECONDS_TO_MS = 1e3;
18803
19431
  const FRAME_ROOT_TIMER_NAMES = /* @__PURE__ */ new Set(["FEngineLoop::Tick"]);
18804
19432
  function parseCsvRows(text) {
@@ -18891,6 +19519,9 @@ function summarizeTimerStatistics(rows, maxScopes) {
18891
19519
  if (count !== void 0) scope.count = count;
18892
19520
  scopes.push(scope);
18893
19521
  }
19522
+ return rankScopes(scopes, maxScopes);
19523
+ }
19524
+ function rankScopes(scopes, maxScopes) {
18894
19525
  const byInclusiveTime = [...scopes].sort((left, right) => right.inclusiveTimeMs - left.inclusiveTimeMs);
18895
19526
  return {
18896
19527
  byExclusiveTime: [...scopes].sort((left, right) => right.exclusiveTimeMs - left.exclusiveTimeMs).slice(0, maxScopes),
@@ -18902,18 +19533,20 @@ function summarizeTimerStatistics(rows, maxScopes) {
18902
19533
  function isGpuThread(threadName) {
18903
19534
  return threadName.toUpperCase().includes("GPU");
18904
19535
  }
18905
- async function summarizeTimingEventStream(lines, options) {
19536
+ async function forEachTimingEvent(lines, visit) {
18906
19537
  let headers;
18907
19538
  let threadIndex = -1;
18908
19539
  let timerIndex = -1;
18909
19540
  let durationIndex = -1;
18910
19541
  let startIndex = -1;
18911
19542
  let depthIndex = -1;
18912
- let cpuTimeMs = 0;
18913
- let gpuTimeMs = 0;
18914
- const frameDurationsMs = [];
18915
- const worstHitches = [];
18916
- let hitchCount = 0;
19543
+ const event = {
19544
+ depth: 0,
19545
+ durationMs: 0,
19546
+ startTimeMs: 0,
19547
+ threadName: "",
19548
+ timerName: ""
19549
+ };
18917
19550
  for await (const rawLine of lines) {
18918
19551
  const line = rawLine.trim();
18919
19552
  if (line.length === 0) continue;
@@ -18926,36 +19559,160 @@ async function summarizeTimingEventStream(lines, options) {
18926
19559
  durationIndex = columnIndex(headers, findColumn(headerRow, "Duration", "InclusiveTime"));
18927
19560
  startIndex = columnIndex(headers, findColumn(headerRow, "StartTime", "Start"));
18928
19561
  depthIndex = columnIndex(headers, findColumn(headerRow, "Depth"));
18929
- if (threadIndex < 0 || durationIndex < 0) break;
19562
+ if (threadIndex < 0 || durationIndex < 0) return;
18930
19563
  continue;
18931
19564
  }
18932
19565
  const duration = readNumber(values[durationIndex]);
18933
19566
  const threadName = values[threadIndex];
18934
19567
  if (duration === void 0 || threadName === void 0) continue;
18935
- if ((depthIndex < 0 ? 0 : readNumber(values[depthIndex]) ?? 0) !== 0) continue;
18936
- const durationMs = duration * SECONDS_TO_MS;
18937
- if (isGpuThread(threadName)) {
18938
- gpuTimeMs += durationMs;
18939
- continue;
19568
+ event.depth = depthIndex < 0 ? 0 : readNumber(values[depthIndex]) ?? 0;
19569
+ event.durationMs = duration * SECONDS_TO_MS;
19570
+ event.startTimeMs = (startIndex < 0 ? 0 : readNumber(values[startIndex]) ?? 0) * SECONDS_TO_MS;
19571
+ event.threadName = threadName;
19572
+ event.timerName = timerIndex < 0 ? "" : values[timerIndex] ?? "";
19573
+ visit(event);
19574
+ }
19575
+ }
19576
+ var ScopeAncestry = class {
19577
+ names = [];
19578
+ threadName;
19579
+ enter(event) {
19580
+ if (event.threadName !== this.threadName) {
19581
+ this.threadName = event.threadName;
19582
+ this.names.length = 0;
18940
19583
  }
18941
- cpuTimeMs += durationMs;
18942
- if (timerIndex < 0 || !FRAME_ROOT_TIMER_NAMES.has(values[timerIndex] ?? "")) continue;
18943
- frameDurationsMs.push(durationMs);
18944
- if (durationMs < options.hitchThresholdMs) continue;
19584
+ this.names.length = Math.min(this.names.length, event.depth);
19585
+ const parentName = event.depth > 0 ? this.names[event.depth - 1] : void 0;
19586
+ this.names[event.depth] = event.timerName;
19587
+ return parentName;
19588
+ }
19589
+ hasOpenAncestorNamed(event) {
19590
+ return this.names.slice(0, event.depth).includes(event.timerName);
19591
+ }
19592
+ };
19593
+ async function summarizeTimingEventStream(lines, options) {
19594
+ let cpuTimeMs = 0;
19595
+ let gpuTimeMs = 0;
19596
+ const frameDurationsMs = [];
19597
+ const worstHitches = [];
19598
+ let hitchCount = 0;
19599
+ const gpuScopeTotals = /* @__PURE__ */ new Map();
19600
+ const gpuAncestry = new ScopeAncestry();
19601
+ await forEachTimingEvent(lines, (event) => {
19602
+ if (isGpuThread(event.threadName)) {
19603
+ accumulateGpuScope(gpuScopeTotals, gpuAncestry, event);
19604
+ if (event.depth === 0) gpuTimeMs += event.durationMs;
19605
+ return;
19606
+ }
19607
+ if (event.depth !== 0) return;
19608
+ cpuTimeMs += event.durationMs;
19609
+ if (!FRAME_ROOT_TIMER_NAMES.has(event.timerName)) return;
19610
+ frameDurationsMs.push(event.durationMs);
19611
+ if (event.durationMs < options.hitchThresholdMs) return;
18945
19612
  hitchCount += 1;
18946
19613
  retainWorstHitch(worstHitches, options.maxHitches, {
18947
- durationMs,
18948
- startTimeMs: (startIndex < 0 ? 0 : readNumber(values[startIndex]) ?? 0) * SECONDS_TO_MS
19614
+ durationMs: event.durationMs,
19615
+ startTimeMs: event.startTimeMs,
19616
+ topScopes: []
18949
19617
  });
18950
- }
19618
+ });
18951
19619
  return {
18952
19620
  frames: summarizeFrameDurations(frameDurationsMs, worstHitches, hitchCount, options),
19621
+ gpuScopes: rankScopeTotals(gpuScopeTotals, options.maxScopes),
18953
19622
  threads: {
18954
19623
  cpuTimeMs,
18955
19624
  gpuTimeMs
18956
19625
  }
18957
19626
  };
18958
19627
  }
19628
+ function accumulateGpuScope(totals, ancestry, event) {
19629
+ const parentName = ancestry.enter(event);
19630
+ const scope = scopeTotalsFor(totals, event.timerName);
19631
+ scope.count += 1;
19632
+ scope.exclusiveTimeMs += event.durationMs;
19633
+ if (!ancestry.hasOpenAncestorNamed(event)) scope.inclusiveTimeMs += event.durationMs;
19634
+ if (parentName !== void 0) scopeTotalsFor(totals, parentName).exclusiveTimeMs -= event.durationMs;
19635
+ }
19636
+ function scopeTotalsFor(totals, name) {
19637
+ const existing = totals.get(name);
19638
+ if (existing !== void 0) return existing;
19639
+ const created = {
19640
+ count: 0,
19641
+ exclusiveTimeMs: 0,
19642
+ inclusiveTimeMs: 0
19643
+ };
19644
+ totals.set(name, created);
19645
+ return created;
19646
+ }
19647
+ function rankScopeTotals(totals, maxScopes) {
19648
+ return rankScopes([...totals].map(([name, scope]) => ({
19649
+ count: scope.count,
19650
+ exclusiveTimeMs: scope.exclusiveTimeMs,
19651
+ inclusiveTimeMs: scope.inclusiveTimeMs,
19652
+ name
19653
+ })), maxScopes);
19654
+ }
19655
+ const SCOPE_KEY_SEPARATOR = "\0";
19656
+ const IDLE_TIMER_NAMES = /* @__PURE__ */ new Set(["TaskWorkerIsLookingForWork", "WaitForTasks"]);
19657
+ async function attributeHitchScopes(lines, hitches, maxScopesPerHitch) {
19658
+ if (hitches.length === 0) return [];
19659
+ const windows = hitches.map((hitch) => ({
19660
+ endTimeMs: hitch.startTimeMs + hitch.durationMs,
19661
+ exclusiveByScope: /* @__PURE__ */ new Map(),
19662
+ hitch,
19663
+ startTimeMs: hitch.startTimeMs
19664
+ })).sort((left, right) => left.startTimeMs - right.startTimeMs);
19665
+ const ancestry = new ScopeAncestry();
19666
+ await forEachTimingEvent(lines, (event) => {
19667
+ if (isGpuThread(event.threadName)) return;
19668
+ const parentName = ancestry.enter(event);
19669
+ const eventEndMs = event.startTimeMs + event.durationMs;
19670
+ for (let index = firstWindowEndingAfter(windows, event.startTimeMs); index < windows.length && (windows[index]?.startTimeMs ?? Number.POSITIVE_INFINITY) < eventEndMs; index += 1) {
19671
+ const window = windows[index];
19672
+ if (window === void 0) break;
19673
+ const overlapMs = Math.min(eventEndMs, window.endTimeMs) - Math.max(event.startTimeMs, window.startTimeMs);
19674
+ if (overlapMs <= 0) continue;
19675
+ addScopeTime(window.exclusiveByScope, event.threadName, event.timerName, overlapMs);
19676
+ if (parentName !== void 0) addScopeTime(window.exclusiveByScope, event.threadName, parentName, -overlapMs);
19677
+ }
19678
+ });
19679
+ return hitches.map((hitch) => {
19680
+ const window = windows.find((candidate) => candidate.hitch === hitch);
19681
+ return {
19682
+ ...hitch,
19683
+ topScopes: window === void 0 ? [] : topHitchScopes(window, maxScopesPerHitch)
19684
+ };
19685
+ });
19686
+ }
19687
+ function firstWindowEndingAfter(windows, timeMs) {
19688
+ let low = 0;
19689
+ let high = windows.length;
19690
+ while (low < high) {
19691
+ const middle = low + high >>> 1;
19692
+ if ((windows[middle]?.endTimeMs ?? Number.POSITIVE_INFINITY) <= timeMs) low = middle + 1;
19693
+ else high = middle;
19694
+ }
19695
+ return low;
19696
+ }
19697
+ function addScopeTime(exclusiveByScope, threadName, timerName, ms) {
19698
+ const key = `${threadName}${SCOPE_KEY_SEPARATOR}${timerName}`;
19699
+ exclusiveByScope.set(key, (exclusiveByScope.get(key) ?? 0) + ms);
19700
+ }
19701
+ function topHitchScopes(window, maxScopes) {
19702
+ const scopes = [];
19703
+ for (const [key, exclusiveTimeMs] of window.exclusiveByScope) {
19704
+ if (exclusiveTimeMs <= 1e-6) continue;
19705
+ const separatorAt = key.indexOf(SCOPE_KEY_SEPARATOR);
19706
+ const name = key.slice(separatorAt + 1);
19707
+ if (IDLE_TIMER_NAMES.has(name)) continue;
19708
+ scopes.push({
19709
+ exclusiveTimeMs,
19710
+ name,
19711
+ threadName: key.slice(0, separatorAt)
19712
+ });
19713
+ }
19714
+ return scopes.sort((left, right) => right.exclusiveTimeMs - left.exclusiveTimeMs).slice(0, maxScopes);
19715
+ }
18959
19716
  function retainWorstHitch(worstHitches, maxHitches, hitch) {
18960
19717
  if (worstHitches.length >= maxHitches) {
18961
19718
  const weakest = worstHitches[worstHitches.length - 1];
@@ -18991,16 +19748,53 @@ function percentile(sortedValues, fraction) {
18991
19748
  if (sortedValues.length === 0) return 0;
18992
19749
  return sortedValues[Math.min(sortedValues.length - 1, Math.max(0, Math.ceil(fraction * sortedValues.length) - 1))] ?? 0;
18993
19750
  }
19751
+ function llmTagNameFromCounter(counterName) {
19752
+ return counterName.replace(/^STAT_/u, "").replace(/LLM$/u, "");
19753
+ }
19754
+ async function summarizeMemoryTagCounter(name, lines) {
19755
+ let valueIndex = -1;
19756
+ let finalBytes;
19757
+ let peakBytes = Number.NEGATIVE_INFINITY;
19758
+ let sawHeader = false;
19759
+ for await (const rawLine of lines) {
19760
+ const line = rawLine.trim();
19761
+ if (line.length === 0) continue;
19762
+ const values = parseCsvLine(line);
19763
+ if (!sawHeader) {
19764
+ sawHeader = true;
19765
+ valueIndex = values.findIndex((header) => header.toLowerCase() === "value");
19766
+ if (valueIndex < 0) return;
19767
+ continue;
19768
+ }
19769
+ const value = readNumber(values[valueIndex]);
19770
+ if (value === void 0) continue;
19771
+ finalBytes = value;
19772
+ peakBytes = Math.max(peakBytes, value);
19773
+ }
19774
+ return finalBytes === void 0 ? void 0 : {
19775
+ finalBytes,
19776
+ name,
19777
+ peakBytes
19778
+ };
19779
+ }
19780
+ function rankMemoryTags(tags, maxTags) {
19781
+ return {
19782
+ tags: [...tags].sort((left, right) => right.peakBytes - left.peakBytes).slice(0, maxTags),
19783
+ totalTagCount: tags.length,
19784
+ truncated: tags.length > maxTags
19785
+ };
19786
+ }
18994
19787
  //#endregion
18995
19788
  //#region src/tools/diagnostics.ts
18996
19789
  const ANALYZE_TRACE_DEFAULT_TIMEOUT_MS = 6e5;
18997
19790
  const ANALYZE_TRACE_DEFAULT_HITCH_THRESHOLD_MS = 33.4;
18998
19791
  const ANALYZE_TRACE_MAX_RESPONSE_BYTES = 32768;
19792
+ const LLM_COUNTER_FILE_PREFIX = "llm-";
18999
19793
  const analyzeTraceInputSchema = {
19000
19794
  engineVersion: engineVersionSchema,
19001
19795
  hitchThresholdMs: z.number().min(1).max(1e4).optional().describe(`Frame duration at or above which a frame counts as a hitch (default ${String(ANALYZE_TRACE_DEFAULT_HITCH_THRESHOLD_MS)}ms, about two frames at 60Hz).`),
19002
19796
  maxHitches: z.number().int().min(1).max(50).optional().describe(`Maximum worst-hitch entries to return (default ${String(10)}, max ${String(50)}).`),
19003
- maxScopes: z.number().int().min(1).max(100).optional().describe(`Maximum timing scopes to return per ranking (default ${String(20)}, max ${String(100)}).`),
19797
+ maxScopes: z.number().int().min(1).max(100).optional().describe(`Maximum timing scopes, GPU scopes and memory tags to return per ranking (default ${String(20)}, max ${String(100)}).`),
19004
19798
  projectPath: z.string().trim().min(1).optional().describe("Project whose EngineAssociation selects the analyzer engine. Omit when engineVersion is given."),
19005
19799
  timeoutMs: z.number().int().min(1e3).max(MAX_PROCESS_TIMEOUT_MS).optional().describe(`Hard timeout in milliseconds for the analyzer run (default ${String(ANALYZE_TRACE_DEFAULT_TIMEOUT_MS)}).`),
19006
19800
  tracePath: z.string().trim().min(1).describe("Path to the .utrace file produced by stop_insights_trace.")
@@ -19016,8 +19810,10 @@ async function analyzeTrace(input, dependencies, context = createEngineToolchain
19016
19810
  engineVersion: engine.engineVersion,
19017
19811
  hitchThresholdMs,
19018
19812
  hitches: [],
19813
+ memoryTags: [],
19019
19814
  reason: `UnrealInsights was not found under ${path.join(engine.engineRoot, "Engine", "Binaries")}; the installed UE ${engine.engineVersion} does not ship the trace analyzer for this host.`,
19020
19815
  state: "unsupported",
19816
+ topGpuScopes: [],
19021
19817
  topScopesByExclusiveTime: [],
19022
19818
  topScopesByInclusiveTime: [],
19023
19819
  tracePath,
@@ -19029,7 +19825,11 @@ async function analyzeTrace(input, dependencies, context = createEngineToolchain
19029
19825
  const timingEventsPath = path.join(exportDirectory, "timing-events.csv");
19030
19826
  const commandFilePath = path.join(exportDirectory, "export.rsp");
19031
19827
  try {
19032
- await context.writeFile(commandFilePath, [`TimingInsights.ExportTimerStatistics ${quoteConsoleArgument(timerStatisticsPath)}`, `TimingInsights.ExportTimingEvents ${quoteConsoleArgument(timingEventsPath)} -columns=ThreadName,TimerName,StartTime,Duration,Depth`].join("\n"));
19828
+ await context.writeFile(commandFilePath, [
19829
+ `TimingInsights.ExportTimerStatistics ${quoteConsoleArgument(timerStatisticsPath)}`,
19830
+ `TimingInsights.ExportTimingEvents ${quoteConsoleArgument(timingEventsPath)} -columns=ThreadName,TimerName,StartTime,Duration,Depth`,
19831
+ `TimingInsights.ExportCounterValues ${quoteConsoleArgument(path.join(exportDirectory, `${LLM_COUNTER_FILE_PREFIX}{counter}.csv`))} -counter=${LLM_TAG_COUNTER_PATTERN}`
19832
+ ].join("\n"));
19033
19833
  dependencies.logger.info({
19034
19834
  engineVersion: engine.engineVersion,
19035
19835
  tracePath
@@ -19049,16 +19849,24 @@ async function analyzeTrace(input, dependencies, context = createEngineToolchain
19049
19849
  });
19050
19850
  if (run.timedOut) throw new EngineToolchainError(`Unreal Insights did not finish analyzing ${tracePath} within ${String(timeoutMs)}ms; raise timeoutMs or trim the trace.`);
19051
19851
  if (run.exitCode !== 0) throw new EngineToolchainError(`Unreal Insights exited with code ${String(run.exitCode)} while analyzing ${tracePath}: ${run.combinedOutput.slice(-1e3).trim()}`);
19052
- const scopeSummaries = summarizeTimerStatistics(await readCsvRows(timerStatisticsPath, context), input.maxScopes ?? 20);
19053
- const timingEvents = await summarizeTimingEventStream(await context.fileExists(timingEventsPath) ? context.readTextLines(timingEventsPath) : emptyTextLines(), {
19852
+ const maxScopes = input.maxScopes ?? 20;
19853
+ const scopeSummaries = summarizeTimerStatistics(await readCsvRows(timerStatisticsPath, context), maxScopes);
19854
+ const hasTimingEvents = await context.fileExists(timingEventsPath);
19855
+ const readTimingEventLines = () => hasTimingEvents ? context.readTextLines(timingEventsPath) : emptyTextLines();
19856
+ const timingEvents = await summarizeTimingEventStream(readTimingEventLines(), {
19054
19857
  hitchThresholdMs,
19055
- maxHitches: input.maxHitches ?? 10
19858
+ maxHitches: input.maxHitches ?? 10,
19859
+ maxScopes
19056
19860
  });
19057
19861
  const frames = timingEvents.frames;
19058
19862
  const threadTimes = timingEvents.threads;
19863
+ const hitches = await attributeHitchScopes(readTimingEventLines(), frames.hitches, 5);
19864
+ const memoryTags = await summarizeMemoryTags(exportDirectory, maxScopes, context);
19059
19865
  const truncated = [];
19060
19866
  if (scopeSummaries.truncated) truncated.push("topScopes");
19061
19867
  if (frames.hitchesTruncated) truncated.push("hitches");
19868
+ if (timingEvents.gpuScopes.truncated) truncated.push("topGpuScopes");
19869
+ if (memoryTags.truncated) truncated.push("memoryTags");
19062
19870
  const result = {
19063
19871
  analyzerPath,
19064
19872
  cpuTimeMs: threadTimes.cpuTimeMs,
@@ -19068,10 +19876,14 @@ async function analyzeTrace(input, dependencies, context = createEngineToolchain
19068
19876
  frameCount: frames.frameCount,
19069
19877
  gpuTimeMs: threadTimes.gpuTimeMs,
19070
19878
  hitchThresholdMs,
19071
- hitches: frames.hitches,
19879
+ hitches,
19880
+ memoryTags: memoryTags.tags,
19072
19881
  state: "analyzed",
19882
+ topGpuScopes: timingEvents.gpuScopes.byExclusiveTime,
19073
19883
  topScopesByExclusiveTime: scopeSummaries.byExclusiveTime,
19074
19884
  topScopesByInclusiveTime: scopeSummaries.byInclusiveTime,
19885
+ totalGpuScopeCount: timingEvents.gpuScopes.totalScopeCount,
19886
+ totalMemoryTagCount: memoryTags.totalTagCount,
19075
19887
  totalScopeCount: scopeSummaries.totalScopeCount,
19076
19888
  tracePath,
19077
19889
  truncated
@@ -19117,22 +19929,42 @@ function boundAnalyzeTraceResult(result) {
19117
19929
  truncated: [...result.truncated]
19118
19930
  };
19119
19931
  while (JSON.stringify(bounded).length > ANALYZE_TRACE_MAX_RESPONSE_BYTES) {
19120
- const longestListLength = Math.max(bounded.topScopesByInclusiveTime.length, bounded.topScopesByExclusiveTime.length, bounded.hitches.length);
19932
+ const topScopesLength = Math.max(bounded.topScopesByInclusiveTime.length, bounded.topScopesByExclusiveTime.length);
19933
+ const longestListLength = Math.max(topScopesLength, bounded.hitches.length, bounded.topGpuScopes.length, bounded.memoryTags.length);
19121
19934
  if (longestListLength <= 1) {
19122
19935
  addTruncationReason(bounded, "responseBytesExceeded");
19123
19936
  return bounded;
19124
19937
  }
19125
- if (bounded.topScopesByInclusiveTime.length === longestListLength) {
19938
+ if (topScopesLength === longestListLength) {
19126
19939
  bounded.topScopesByInclusiveTime = bounded.topScopesByInclusiveTime.slice(0, longestListLength - 1);
19127
19940
  bounded.topScopesByExclusiveTime = bounded.topScopesByExclusiveTime.slice(0, longestListLength - 1);
19128
19941
  addTruncationReason(bounded, "topScopes");
19129
19942
  continue;
19130
19943
  }
19944
+ if (bounded.topGpuScopes.length === longestListLength) {
19945
+ bounded.topGpuScopes = bounded.topGpuScopes.slice(0, longestListLength - 1);
19946
+ addTruncationReason(bounded, "topGpuScopes");
19947
+ continue;
19948
+ }
19949
+ if (bounded.memoryTags.length === longestListLength) {
19950
+ bounded.memoryTags = bounded.memoryTags.slice(0, longestListLength - 1);
19951
+ addTruncationReason(bounded, "memoryTags");
19952
+ continue;
19953
+ }
19131
19954
  bounded.hitches = bounded.hitches.slice(0, bounded.hitches.length - 1);
19132
19955
  addTruncationReason(bounded, "hitches");
19133
19956
  }
19134
19957
  return bounded;
19135
19958
  }
19959
+ async function summarizeMemoryTags(exportDirectory, maxTags, context) {
19960
+ const counterFiles = (await context.listDirectory(exportDirectory)).filter((fileName) => fileName.startsWith(LLM_COUNTER_FILE_PREFIX) && fileName.endsWith(".csv"));
19961
+ const tags = [];
19962
+ for (const fileName of counterFiles) {
19963
+ const tag = await summarizeMemoryTagCounter(llmTagNameFromCounter(fileName.slice(4, -4)), context.readTextLines(path.join(exportDirectory, fileName)));
19964
+ if (tag !== void 0) tags.push(tag);
19965
+ }
19966
+ return rankMemoryTags(tags, maxTags);
19967
+ }
19136
19968
  function addTruncationReason(result, reason) {
19137
19969
  if (!result.truncated.includes(reason)) result.truncated.push(reason);
19138
19970
  }
@@ -19270,7 +20102,7 @@ function registerDiagnosticsTools(server, dependencies) {
19270
20102
  }, dependencies));
19271
20103
  });
19272
20104
  server.registerTool("analyze_trace", {
19273
- description: "Analyze a completed .utrace (the path stop_insights_trace returns) headlessly with the engine's Unreal Insights analyzer and return a bounded, readable summary: frame-time p50/p90/p99, the worst N hitches with timestamps, a CPU vs GPU time split, and top-N timing scopes by inclusive and exclusive time. Memory and LLM-tag totals are deliberately not reported — they need a separate analysis pass. Resolve the engine with engineVersion or projectPath. Every list is top-N and the response is byte-capped, with truncated naming what was shortened. Returns state 'unsupported' when the installed engine ships no Insights analyzer for this host.",
20105
+ description: "Analyze a completed .utrace (the path stop_insights_trace returns) headlessly with the engine's Unreal Insights analyzer and return a bounded, readable summary: frame-time p50/p90/p99, the worst N hitches with timestamps and each hitch's top 5 CPU scopes by exclusive time inside its window (with thread names, task-system idle waits left out), a CPU vs GPU time split, top-N timing scopes by inclusive and exclusive time, top-N GPU scopes by exclusive time, and LLM memory tags with their final and peak bytes. Memory tags are only present when the trace was captured with LLM enabled (-llm) and the stats channel. Resolve the engine with engineVersion or projectPath. Every list is top-N and the response is byte-capped, with truncated naming what was shortened. Returns state 'unsupported' when the installed engine ships no Insights analyzer for this host.",
19274
20106
  inputSchema: analyzeTraceInputSchema,
19275
20107
  title: "Analyze Trace"
19276
20108
  }, async (input) => {
@@ -20111,6 +20943,7 @@ const listGraphNodesInputSchema = {
20111
20943
  };
20112
20944
  const addGraphNodeInputSchema = {
20113
20945
  assetPath: bridgeAddGraphNodeRequestFieldsSchema.shape.assetPath.describe("Package name or object path of the asset owning the graph."),
20946
+ autoLayout: bridgeAddGraphNodeRequestFieldsSchema.shape.autoLayout.describe("Move the new node clear of the graph's existing nodes. Starts from position when given (sliding down until it overlaps nothing), otherwise from just right of the graph's current nodes. Only the new node moves; call layout_graph to rearrange the whole graph."),
20114
20947
  graphName: bridgeAddGraphNodeRequestFieldsSchema.shape.graphName.describe("Graph to add the node to."),
20115
20948
  kind: bridgeAddGraphNodeRequestFieldsSchema.shape.kind.describe("How the node is named: 'class' places a node type directly, 'function' places a call, 'variable_get' / 'variable_set' place a variable accessor."),
20116
20949
  memberName: bridgeAddGraphNodeRequestFieldsSchema.shape.memberName.describe("Function or variable name, required for every kind except 'class'."),
@@ -20152,6 +20985,11 @@ const setPinDefaultInputSchema = {
20152
20985
  projectId: creativeProjectIdSchema,
20153
20986
  value: bridgeSetPinDefaultRequestSchema.shape.value.describe("ExportText value, the same format get_actor_details emits and set_actor_property accepts.")
20154
20987
  };
20988
+ const layoutGraphInputSchema = {
20989
+ assetPath: bridgeLayoutGraphRequestSchema.shape.assetPath.describe("Package name or object path of the Blueprint owning the graph."),
20990
+ graphName: bridgeLayoutGraphRequestSchema.shape.graphName.describe("Graph to arrange, as get_blueprint_summary reports it (e.g. 'EventGraph')."),
20991
+ projectId: creativeProjectIdSchema
20992
+ };
20155
20993
  const listAvailableNodesInputSchema = {
20156
20994
  assetPath: bridgeListAvailableNodesRequestSchema.shape.assetPath.describe("Package name or object path of the asset owning the graph."),
20157
20995
  cursor: bridgeListAvailableNodesRequestSchema.shape.cursor.describe("nextCursor from a previous response, to fetch the following page."),
@@ -20169,6 +21007,7 @@ async function listGraphNodes(input, dependencies) {
20169
21007
  }
20170
21008
  async function addGraphNode(input, dependencies) {
20171
21009
  return await exchangeCreativeRequest(createBridgeAddGraphNodeRequest(input.assetPath, input.graphName, input.kind, {
21010
+ autoLayout: input.autoLayout,
20172
21011
  memberName: input.memberName,
20173
21012
  memberParentClass: input.memberParentClass,
20174
21013
  nodeClass: input.nodeClass,
@@ -20207,6 +21046,9 @@ async function listAvailableNodes(input, dependencies) {
20207
21046
  nameFilter: input.nameFilter
20208
21047
  }), sendBridgeListAvailableNodesRequest, BRIDGE_LIST_AVAILABLE_NODES_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
20209
21048
  }
21049
+ async function layoutGraph(input, dependencies) {
21050
+ return await exchangeCreativeRequest(createBridgeLayoutGraphRequest(input.assetPath, input.graphName), sendBridgeLayoutGraphRequest, BRIDGE_LAYOUT_GRAPH_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
21051
+ }
20210
21052
  function registerGraphTools(server, dependencies) {
20211
21053
  server.registerTool("list_graph_nodes", {
20212
21054
  description: "List the nodes in any UEdGraph — a Blueprint event graph or function, an Animation Blueprint AnimGraph, a Material graph, a Behavior Tree — with each node's GUID, class, title and pins. The GUID is what every other graph tool addresses a node by; it survives adding and removing other nodes, which an index does not. Results are paged by nextCursor.",
@@ -20223,12 +21065,13 @@ function registerGraphTools(server, dependencies) {
20223
21065
  }, dependencies));
20224
21066
  });
20225
21067
  server.registerTool("add_graph_node", {
20226
- description: "Add a node to a UEdGraph and return it with its pins, so it can be wired without a follow-up read. kind 'class' places a node type directly (K2Node_IfThenElse for a Branch); 'function' places a call to memberName on memberParentClass; 'variable_get' / 'variable_set' place a variable accessor. Use list_available_nodes to discover what this graph's schema accepts rather than guessing class names. pinDefaults configures the node in the same call. The Blueprint is marked structurally modified, so compile_blueprint afterwards picks the change up.",
21068
+ description: "Add a node to a UEdGraph and return it with its pins, so it can be wired without a follow-up read. kind 'class' places a node type directly (K2Node_IfThenElse for a Branch); 'function' places a call to memberName on memberParentClass; 'variable_get' / 'variable_set' place a variable accessor. Use list_available_nodes to discover what this graph's schema accepts rather than guessing class names. pinDefaults configures the node in the same call. autoLayout moves only the new node clear of the existing ones and reports where it landed in position; layout_graph rearranges the whole graph. The Blueprint is marked structurally modified, so compile_blueprint afterwards picks the change up.",
20227
21069
  inputSchema: addGraphNodeInputSchema,
20228
21070
  title: "Add Graph Node"
20229
- }, async ({ assetPath, graphName, kind, memberName, memberParentClass, nodeClass, pinDefaults, position, projectId }) => {
21071
+ }, async ({ assetPath, autoLayout, graphName, kind, memberName, memberParentClass, nodeClass, pinDefaults, position, projectId }) => {
20230
21072
  return toToolSuccess(await addGraphNode({
20231
21073
  assetPath,
21074
+ autoLayout,
20232
21075
  graphName,
20233
21076
  kind,
20234
21077
  memberName,
@@ -20309,6 +21152,17 @@ function registerGraphTools(server, dependencies) {
20309
21152
  projectId
20310
21153
  }, dependencies));
20311
21154
  });
21155
+ server.registerTool("layout_graph", {
21156
+ description: "Auto-arrange a Blueprint graph so no two nodes overlap: exec flow is layered left to right from each event, branches fan out downward, and pure (data) nodes sit in the column left of the node that consumes them. Comment boxes stay where they are. Node sizes are estimated from title and pin count, since an editor without the graph open has no rendered widget to measure. The whole rearrangement is one undo step. Use it after building a graph with add_graph_node; Material graphs are not supported.",
21157
+ inputSchema: layoutGraphInputSchema,
21158
+ title: "Layout Graph"
21159
+ }, async ({ assetPath, graphName, projectId }) => {
21160
+ return toToolSuccess(await layoutGraph({
21161
+ assetPath,
21162
+ graphName,
21163
+ projectId
21164
+ }, dependencies));
21165
+ });
20312
21166
  }
20313
21167
  const graphToolDomain = {
20314
21168
  domain: "graph",
@@ -20320,7 +21174,8 @@ const graphToolDomain = {
20320
21174
  "connect_pins",
20321
21175
  "disconnect_pins",
20322
21176
  "set_pin_default",
20323
- "list_available_nodes"
21177
+ "list_available_nodes",
21178
+ "layout_graph"
20324
21179
  ]
20325
21180
  };
20326
21181
  //#endregion
@@ -22832,6 +23687,95 @@ const logsToolDomain = {
22832
23687
  ]
22833
23688
  };
22834
23689
  //#endregion
23690
+ //#region src/tools/mass.ts
23691
+ const MASS_TRAIT_HINT = "Traits are named by class: 'MassMovementTrait' or 'MassSimpleMovementTrait' (movement), 'MassLODCollectorTrait' or 'MassSimulationLODTrait' (LOD), 'MassVisualizationTrait' or 'MassMovableVisualizationTrait' (representation), 'MassStateTreeTrait' (StateTree behaviour, needs the MassAI plugin), or a '/Script/Module.Class' path.";
23692
+ const createMassEntityConfigInputSchema = {
23693
+ assetName: bridgeCreateMassEntityConfigRequestSchema.shape.assetName.describe("Name of the new MassEntityConfig asset, e.g. 'DA_CrowdAgent'."),
23694
+ packagePath: bridgeCreateMassEntityConfigRequestSchema.shape.packagePath.describe("Content folder to create the config in, e.g. /Game/Mass."),
23695
+ parentConfigPath: bridgeCreateMassEntityConfigRequestSchema.shape.parentConfigPath.describe("Optional MassEntityConfig to inherit traits from; this config overrides any trait of the same class."),
23696
+ projectId: creativeProjectIdSchema
23697
+ };
23698
+ const editMassEntityConfigInputSchema = {
23699
+ assetPath: bridgeEditMassEntityConfigRequestSchema.shape.assetPath.describe("MassEntityConfig asset to edit."),
23700
+ edits: bridgeEditMassEntityConfigRequestSchema.shape.edits.describe(`Trait edits applied in order. 'add' adds the trait (or configures the existing one of that class) and may carry properties; 'set' writes properties on a trait the config owns; 'remove' drops it. properties are { propertyPath, value } pairs in exported-text form, e.g. { propertyPath: 'Movement.MaxSpeed', value: '300' }. ${MASS_TRAIT_HINT}`),
23701
+ projectId: creativeProjectIdSchema
23702
+ };
23703
+ const getMassEntityConfigInputSchema = {
23704
+ assetPath: bridgeGetMassEntityConfigRequestSchema.shape.assetPath.describe("MassEntityConfig asset to read."),
23705
+ projectId: creativeProjectIdSchema
23706
+ };
23707
+ const validateMassEntityConfigInputSchema = {
23708
+ assetPath: bridgeValidateMassEntityConfigRequestSchema.shape.assetPath.describe("MassEntityConfig asset to validate."),
23709
+ projectId: creativeProjectIdSchema
23710
+ };
23711
+ async function createMassEntityConfig(input, dependencies) {
23712
+ return await exchangeCreativeRequest(createBridgeCreateMassEntityConfigRequest(input.assetName, input.packagePath, { parentConfigPath: input.parentConfigPath }), sendBridgeCreateMassEntityConfigRequest, BRIDGE_CREATE_MASS_ENTITY_CONFIG_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
23713
+ }
23714
+ async function editMassEntityConfig(input, dependencies) {
23715
+ return await exchangeCreativeRequest(createBridgeEditMassEntityConfigRequest(input.assetPath, input.edits), sendBridgeEditMassEntityConfigRequest, BRIDGE_EDIT_MASS_ENTITY_CONFIG_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
23716
+ }
23717
+ async function getMassEntityConfig(input, dependencies) {
23718
+ return await exchangeCreativeRequest(createBridgeGetMassEntityConfigRequest(input.assetPath), sendBridgeGetMassEntityConfigRequest, BRIDGE_GET_MASS_ENTITY_CONFIG_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
23719
+ }
23720
+ async function validateMassEntityConfig(input, dependencies) {
23721
+ return await exchangeCreativeRequest(createBridgeValidateMassEntityConfigRequest(input.assetPath), sendBridgeValidateMassEntityConfigRequest, BRIDGE_VALIDATE_MASS_ENTITY_CONFIG_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
23722
+ }
23723
+ function registerMassTools(server, dependencies) {
23724
+ server.registerTool("create_mass_entity_config", {
23725
+ description: "Create a MassEntityConfig data asset — the trait list a Mass crowd agent is spawned from — optionally inheriting from a parent config. Add traits with edit_mass_entity_config. Returns state 'unsupported' with a reason when the Mass plugins are not loaded.",
23726
+ inputSchema: createMassEntityConfigInputSchema,
23727
+ title: "Create Mass Entity Config"
23728
+ }, async ({ assetName, packagePath, parentConfigPath, projectId }) => {
23729
+ return toToolSuccess(await createMassEntityConfig({
23730
+ assetName,
23731
+ packagePath,
23732
+ parentConfigPath,
23733
+ projectId
23734
+ }, dependencies));
23735
+ });
23736
+ server.registerTool("edit_mass_entity_config", {
23737
+ description: "Add, remove and configure the traits of a MassEntityConfig (movement, LOD, representation, StateTree and any other Mass trait). Each edit reports its own outcome, and traits lists the config's own trait classes afterwards. The package is left dirty; save it with save_dirty_packages. Run validate_mass_entity_config to check the result.",
23738
+ inputSchema: editMassEntityConfigInputSchema,
23739
+ title: "Edit Mass Entity Config"
23740
+ }, async ({ assetPath, edits, projectId }) => {
23741
+ return toToolSuccess(await editMassEntityConfig({
23742
+ assetPath,
23743
+ edits,
23744
+ projectId
23745
+ }, dependencies));
23746
+ });
23747
+ server.registerTool("get_mass_entity_config", {
23748
+ description: "Read a MassEntityConfig back: its parent config and each of its own traits with the trait's editable properties as exported text, which edit_mass_entity_config accepts unchanged.",
23749
+ inputSchema: getMassEntityConfigInputSchema,
23750
+ title: "Get Mass Entity Config"
23751
+ }, async ({ assetPath, projectId }) => {
23752
+ return toToolSuccess(await getMassEntityConfig({
23753
+ assetPath,
23754
+ projectId
23755
+ }, dependencies));
23756
+ });
23757
+ server.registerTool("validate_mass_entity_config", {
23758
+ description: "Build the config's entity template the way the asset editor's Validate button does and report whether it is valid, with the engine's own error and warning lines verbatim (for example a trait missing a fragment another trait must provide).",
23759
+ inputSchema: validateMassEntityConfigInputSchema,
23760
+ title: "Validate Mass Entity Config"
23761
+ }, async ({ assetPath, projectId }) => {
23762
+ return toToolSuccess(await validateMassEntityConfig({
23763
+ assetPath,
23764
+ projectId
23765
+ }, dependencies));
23766
+ });
23767
+ }
23768
+ const massToolDomain = {
23769
+ domain: "mass",
23770
+ register: registerMassTools,
23771
+ toolNames: [
23772
+ "create_mass_entity_config",
23773
+ "edit_mass_entity_config",
23774
+ "get_mass_entity_config",
23775
+ "validate_mass_entity_config"
23776
+ ]
23777
+ };
23778
+ //#endregion
22835
23779
  //#region src/tools/material.ts
22836
23780
  const createMaterialInstanceInputSchema = {
22837
23781
  assetName: bridgeCreateMaterialInstanceRequestSchema.shape.assetName.describe("Name of the new instance, e.g. 'MI_Rock_Mossy'."),
@@ -23102,6 +24046,13 @@ const testReachabilityInputSchema = {
23102
24046
  pairs: bridgeTestReachabilityRequestFieldsSchema.shape.pairs.describe(`Start/end pairs to test (max ${String(64)}), each naming exactly one of start/startActorPath and one of end/endActorPath.`),
23103
24047
  projectId: creativeProjectIdSchema
23104
24048
  };
24049
+ const diagnoseNavmeshInputSchema = {
24050
+ includePlayerStarts: bridgeDiagnoseNavmeshRequestSchema.shape.includePlayerStarts.describe("Check every PlayerStart in the level as a spawn point. Defaults to true."),
24051
+ maxIslands: bridgeDiagnoseNavmeshRequestSchema.shape.maxIslands.describe(`Most islands to list, largest area first (1-${String(64)}). islandCount stays the full count.`),
24052
+ navMeshActorPath: bridgeDiagnoseNavmeshRequestSchema.shape.navMeshActorPath.describe("Actor path of the RecastNavMesh to inspect. Omit to use the level's main navigation data."),
24053
+ projectId: creativeProjectIdSchema,
24054
+ spawnActorPaths: bridgeDiagnoseNavmeshRequestSchema.shape.spawnActorPaths.describe(`Extra spawn actors to check alongside the player starts, such as AI spawners (max ${String(64)}).`)
24055
+ };
23105
24056
  async function setNavmeshSettings(input, dependencies) {
23106
24057
  return await exchangeCreativeRequest(createBridgeSetNavmeshSettingsRequest({
23107
24058
  agentHeight: input.agentHeight,
@@ -23172,6 +24123,14 @@ async function testReachability(input, dependencies) {
23172
24123
  navMeshActorPath: input.navMeshActorPath
23173
24124
  }), sendBridgeTestReachabilityRequest, BRIDGE_TEST_REACHABILITY_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
23174
24125
  }
24126
+ async function diagnoseNavmesh(input, dependencies) {
24127
+ return await exchangeCreativeRequest(createBridgeDiagnoseNavmeshRequest({
24128
+ includePlayerStarts: input.includePlayerStarts,
24129
+ maxIslands: input.maxIslands,
24130
+ navMeshActorPath: input.navMeshActorPath,
24131
+ spawnActorPaths: input.spawnActorPaths
24132
+ }), sendBridgeDiagnoseNavmeshRequest, BRIDGE_DIAGNOSE_NAVMESH_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
24133
+ }
23175
24134
  function registerNavigationTools(server, dependencies) {
23176
24135
  server.registerTool("set_navmesh_settings", {
23177
24136
  description: "Write the level's navmesh generation settings — agent radius and height, max slope and step height, voxel cell size, tile size and runtime generation mode. The values only reach the navmesh on the next build, so follow this with build_navigation. Returns every setting as it stands after the write, so a clamped value is visible.",
@@ -23289,6 +24248,19 @@ function registerNavigationTools(server, dependencies) {
23289
24248
  projectId
23290
24249
  }, dependencies));
23291
24250
  });
24251
+ server.registerTool("diagnose_navmesh", {
24252
+ description: "Audit the editor level's navmesh without changing it: missing nav bounds, an empty navmesh, disconnected islands (poly count, area and bounds, largest area first), and player starts or named AI spawn actors that sit off the navmesh or cannot path to the first spawn point. Each finding is listed in issues with a code; healthy is true when there are none.",
24253
+ inputSchema: diagnoseNavmeshInputSchema,
24254
+ title: "Diagnose Navmesh"
24255
+ }, async ({ includePlayerStarts, maxIslands, navMeshActorPath, projectId, spawnActorPaths }) => {
24256
+ return toToolSuccess(await diagnoseNavmesh({
24257
+ includePlayerStarts,
24258
+ maxIslands,
24259
+ navMeshActorPath,
24260
+ projectId,
24261
+ spawnActorPaths
24262
+ }, dependencies));
24263
+ });
23292
24264
  }
23293
24265
  const navigationToolDomain = {
23294
24266
  domain: "navigation",
@@ -23301,7 +24273,8 @@ const navigationToolDomain = {
23301
24273
  "add_nav_modifier_volume",
23302
24274
  "add_nav_link",
23303
24275
  "find_path",
23304
- "test_reachability"
24276
+ "test_reachability",
24277
+ "diagnose_navmesh"
23305
24278
  ]
23306
24279
  };
23307
24280
  //#endregion
@@ -24218,6 +25191,90 @@ const sequencerToolDomain = {
24218
25191
  ]
24219
25192
  };
24220
25193
  //#endregion
25194
+ //#region src/tools/smartObjects.ts
25195
+ const createSmartObjectDefinitionInputSchema = {
25196
+ activityTags: bridgeCreateSmartObjectDefinitionRequestSchema.shape.activityTags.describe("Gameplay tags describing what the whole object offers, e.g. 'Activity.Sit'. Every tag must already be registered."),
25197
+ assetName: bridgeCreateSmartObjectDefinitionRequestSchema.shape.assetName.describe("Name of the new Smart Object definition, e.g. 'SOD_Bench'."),
25198
+ defaultBehaviorDefinitions: bridgeCreateSmartObjectDefinitionRequestSchema.shape.defaultBehaviorDefinitions.describe("Behavior definitions every slot without its own falls back to, each { behaviorClass, params? }. behaviorClass names a concrete USmartObjectBehaviorDefinition subclass, e.g. '/Script/GameplayBehaviorSmartObjectsModule.GameplayBehaviorSmartObjectBehaviorDefinition'. A slot with no behavior and no default leaves the definition invalid, and an invalid definition never registers."),
25199
+ packagePath: bridgeCreateSmartObjectDefinitionRequestSchema.shape.packagePath.describe("Content folder to create the definition in."),
25200
+ projectId: creativeProjectIdSchema,
25201
+ slots: bridgeCreateSmartObjectDefinitionRequestSchema.shape.slots.describe("Slots users claim, each { name?, offset?: {x,y,z}, rotation?: {pitch,yaw,roll}, enabled?, activityTags?, behaviorDefinitions? }. Offset and rotation are relative to the owning actor.")
25202
+ };
25203
+ const getSmartObjectDefinitionInputSchema = {
25204
+ assetPath: bridgeGetSmartObjectDefinitionRequestSchema.shape.assetPath.describe("Object path of the Smart Object definition to read."),
25205
+ projectId: creativeProjectIdSchema
25206
+ };
25207
+ const addSmartObjectComponentInputSchema = {
25208
+ actorPath: bridgeAddSmartObjectComponentRequestFieldsSchema.shape.actorPath.describe("Placed actor in the editor level to add the component to. Give this or blueprintPath, not both."),
25209
+ blueprintPath: bridgeAddSmartObjectComponentRequestFieldsSchema.shape.blueprintPath.describe("Actor Blueprint to add the component to; the Blueprint is recompiled. Give this or actorPath, not both."),
25210
+ componentName: bridgeAddSmartObjectComponentRequestFieldsSchema.shape.componentName.describe("Name of the component. Omitted reuses the existing Smart Object component, or names a new one SmartObject."),
25211
+ definitionPath: bridgeAddSmartObjectComponentRequestFieldsSchema.shape.definitionPath.describe("Smart Object definition the component points at."),
25212
+ projectId: creativeProjectIdSchema
25213
+ };
25214
+ async function createSmartObjectDefinition(input, dependencies) {
25215
+ return await exchangeCreativeRequest(createBridgeCreateSmartObjectDefinitionRequest(input.assetName, input.packagePath, input.slots, {
25216
+ activityTags: input.activityTags,
25217
+ defaultBehaviorDefinitions: input.defaultBehaviorDefinitions
25218
+ }), sendBridgeCreateSmartObjectDefinitionRequest, BRIDGE_CREATE_SMART_OBJECT_DEFINITION_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
25219
+ }
25220
+ async function getSmartObjectDefinition(input, dependencies) {
25221
+ return await exchangeCreativeRequest(createBridgeGetSmartObjectDefinitionRequest(input.assetPath), sendBridgeGetSmartObjectDefinitionRequest, BRIDGE_GET_SMART_OBJECT_DEFINITION_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
25222
+ }
25223
+ async function addSmartObjectComponent(input, dependencies) {
25224
+ return await exchangeCreativeRequest(createBridgeAddSmartObjectComponentRequest(input.definitionPath, {
25225
+ actorPath: input.actorPath,
25226
+ blueprintPath: input.blueprintPath
25227
+ }, { componentName: input.componentName }), sendBridgeAddSmartObjectComponentRequest, BRIDGE_ADD_SMART_OBJECT_COMPONENT_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
25228
+ }
25229
+ function registerSmartObjectsTools(server, dependencies) {
25230
+ server.registerTool("create_smart_object_definition", {
25231
+ description: "Create a Smart Object definition with its slots — offsets, rotations, activity tags and behavior definitions — and read back what the asset holds, including whether it passes the engine's validation. An invalid definition never registers, so check 'valid' before placing it. Returns state 'unsupported' when the SmartObjects plugin is not loaded.",
25232
+ inputSchema: createSmartObjectDefinitionInputSchema,
25233
+ title: "Create Smart Object Definition"
25234
+ }, async ({ activityTags, assetName, defaultBehaviorDefinitions, packagePath, projectId, slots }) => {
25235
+ return toToolSuccess(await createSmartObjectDefinition({
25236
+ activityTags,
25237
+ assetName,
25238
+ defaultBehaviorDefinitions,
25239
+ packagePath,
25240
+ projectId,
25241
+ slots
25242
+ }, dependencies));
25243
+ });
25244
+ server.registerTool("get_smart_object_definition", {
25245
+ description: "Read a Smart Object definition: its slots, activity tags, behavior definitions and validation result. Returns state 'unsupported' when the SmartObjects plugin is not loaded.",
25246
+ inputSchema: getSmartObjectDefinitionInputSchema,
25247
+ title: "Get Smart Object Definition"
25248
+ }, async ({ assetPath, projectId }) => {
25249
+ return toToolSuccess(await getSmartObjectDefinition({
25250
+ assetPath,
25251
+ projectId
25252
+ }, dependencies));
25253
+ });
25254
+ server.registerTool("add_smart_object_component", {
25255
+ description: "Add a Smart Object component pointing at a definition to an actor Blueprint or a placed actor, or repoint the one already there. The component registers with the Smart Object subsystem when play begins, which needs a valid definition — 'definitionValid' says whether it will. Returns state 'unsupported' when the SmartObjects plugin is not loaded.",
25256
+ inputSchema: addSmartObjectComponentInputSchema,
25257
+ title: "Add Smart Object Component"
25258
+ }, async ({ actorPath, blueprintPath, componentName, definitionPath, projectId }) => {
25259
+ return toToolSuccess(await addSmartObjectComponent({
25260
+ actorPath,
25261
+ blueprintPath,
25262
+ componentName,
25263
+ definitionPath,
25264
+ projectId
25265
+ }, dependencies));
25266
+ });
25267
+ }
25268
+ const smartObjectsToolDomain = {
25269
+ domain: "smartObjects",
25270
+ register: registerSmartObjectsTools,
25271
+ toolNames: [
25272
+ "create_smart_object_definition",
25273
+ "get_smart_object_definition",
25274
+ "add_smart_object_component"
25275
+ ]
25276
+ };
25277
+ //#endregion
24221
25278
  //#region src/tools/stateTree.ts
24222
25279
  const getStateTreeInputSchema = {
24223
25280
  assetPath: bridgeGetStateTreeRequestSchema.shape.assetPath.describe("Object path of the StateTree asset to read."),
@@ -24256,6 +25313,18 @@ const traceStateTreeInputSchema = {
24256
25313
  maxEvents: bridgeTraceStateTreeRequestSchema.shape.maxEvents.describe("Maximum events to return in one poll (1-200, default 50)."),
24257
25314
  projectId: creativeProjectIdSchema
24258
25315
  };
25316
+ const updateStateTreeElementsInputSchema = {
25317
+ assetPath: bridgeUpdateStateTreeElementsRequestSchema.shape.assetPath.describe("Object path of the StateTree asset to edit."),
25318
+ compile: bridgeUpdateStateTreeElementsRequestSchema.shape.compile.describe("Run the StateTree compiler after the edits. Defaults true; its messages come back verbatim in compileMessages."),
25319
+ projectId: creativeProjectIdSchema,
25320
+ updates: bridgeUpdateStateTreeElementsRequestSchema.shape.updates.describe("Edits addressed by the ids get_state_tree reports. { kind: 'state', id, name?, stateType?, selectionBehavior?, enabled? } renames or retypes a state (renaming keeps transitions pointing at it); { kind: 'task', id, params } writes ExportText values onto a task; { kind: 'transition', id, trigger?, targetType?, targetStateId?, eventTag?, enabled? } points a transition at a new target or trigger. A targetStateId alone implies targetType 'goto_state'.")
25321
+ };
25322
+ const removeStateTreeElementsInputSchema = {
25323
+ assetPath: bridgeRemoveStateTreeElementsRequestSchema.shape.assetPath.describe("Object path of the StateTree asset to edit."),
25324
+ compile: bridgeRemoveStateTreeElementsRequestSchema.shape.compile.describe("Run the StateTree compiler after the removals. Defaults true; its messages come back verbatim in compileMessages."),
25325
+ projectId: creativeProjectIdSchema,
25326
+ removals: bridgeRemoveStateTreeElementsRequestSchema.shape.removals.describe("Elements to remove, each { kind, id } with kind 'state', 'task' or 'transition' and the id get_state_tree reports. Removing a state removes its children too.")
25327
+ };
24259
25328
  async function getStateTree(input, dependencies) {
24260
25329
  return await exchangeCreativeRequest(createBridgeGetStateTreeRequest(input.assetPath), sendBridgeGetStateTreeRequest, BRIDGE_GET_STATE_TREE_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
24261
25330
  }
@@ -24284,6 +25353,12 @@ async function traceStateTree(input, dependencies) {
24284
25353
  maxEvents: input.maxEvents
24285
25354
  }), sendBridgeTraceStateTreeRequest, BRIDGE_TRACE_STATE_TREE_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
24286
25355
  }
25356
+ async function updateStateTreeElements(input, dependencies) {
25357
+ return await exchangeCreativeRequest(createBridgeUpdateStateTreeElementsRequest(input.assetPath, input.updates, { compile: input.compile }), sendBridgeUpdateStateTreeElementsRequest, BRIDGE_UPDATE_STATE_TREE_ELEMENTS_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
25358
+ }
25359
+ async function removeStateTreeElements(input, dependencies) {
25360
+ return await exchangeCreativeRequest(createBridgeRemoveStateTreeElementsRequest(input.assetPath, input.removals, { compile: input.compile }), sendBridgeRemoveStateTreeElementsRequest, BRIDGE_REMOVE_STATE_TREE_ELEMENTS_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
25361
+ }
24287
25362
  function registerStateTreeTools(server, dependencies) {
24288
25363
  server.registerTool("get_state_tree", {
24289
25364
  description: "Read a StateTree back: its schema, parameters, evaluators, global tasks and the full state hierarchy with each state's tasks, enter conditions and transitions. Every state and node carries the id the edit tools address it by, so this is the call to make before editing a tree you did not author. compiled reports whether the asset carries runtime data — a tree that reads back correctly with compiled false is authored but will not run.",
@@ -24358,6 +25433,30 @@ function registerStateTreeTools(server, dependencies) {
24358
25433
  projectId
24359
25434
  }, dependencies));
24360
25435
  });
25436
+ server.registerTool("update_state_tree_elements", {
25437
+ description: "Edit existing StateTree states, tasks and transitions by the ids get_state_tree reports: rename or retype a state, toggle it, change its selection behaviour; set a task's params; retarget, retrigger or toggle a transition. Each edit is reported per item, and the tree is recompiled by default with the compiler's own messages returned verbatim.",
25438
+ inputSchema: updateStateTreeElementsInputSchema,
25439
+ title: "Update StateTree Elements"
25440
+ }, async ({ assetPath, compile, projectId, updates }) => {
25441
+ return toToolSuccess(await updateStateTreeElements({
25442
+ assetPath,
25443
+ compile,
25444
+ projectId,
25445
+ updates
25446
+ }, dependencies));
25447
+ });
25448
+ server.registerTool("remove_state_tree_elements", {
25449
+ description: "Remove StateTree states, tasks and transitions by the ids get_state_tree reports. Removing a state removes its children and every transition elsewhere in the tree that targeted it; those transitions are listed in removedTransitions. The tree is recompiled by default with the compiler's own messages returned verbatim.",
25450
+ inputSchema: removeStateTreeElementsInputSchema,
25451
+ title: "Remove StateTree Elements"
25452
+ }, async ({ assetPath, compile, projectId, removals }) => {
25453
+ return toToolSuccess(await removeStateTreeElements({
25454
+ assetPath,
25455
+ compile,
25456
+ projectId,
25457
+ removals
25458
+ }, dependencies));
25459
+ });
24361
25460
  }
24362
25461
  const stateTreeToolDomain = {
24363
25462
  domain: "stateTree",
@@ -24368,7 +25467,9 @@ const stateTreeToolDomain = {
24368
25467
  "set_state_tree_considerations",
24369
25468
  "link_state_tree_state",
24370
25469
  "add_state_tree_component",
24371
- "trace_state_tree"
25470
+ "trace_state_tree",
25471
+ "update_state_tree_elements",
25472
+ "remove_state_tree_elements"
24372
25473
  ]
24373
25474
  };
24374
25475
  //#endregion
@@ -25294,7 +26395,9 @@ const TOOL_CATALOG = [
25294
26395
  vfxToolDomain,
25295
26396
  pcgToolDomain,
25296
26397
  projectSettingsToolDomain,
25297
- navigationToolDomain
26398
+ navigationToolDomain,
26399
+ smartObjectsToolDomain,
26400
+ massToolDomain
25298
26401
  ];
25299
26402
  //#endregion
25300
26403
  //#region src/mcpTools.ts