@uemcp/server 1.11.0 → 1.12.1

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 +35 -1
  2. package/dist/index.mjs +1140 -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,368 @@ 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
+ "spawn_cannot_return"
11267
+ ];
11268
+ const BRIDGE_NAV_SPAWN_POINT_KINDS = ["player_start", "actor"];
11269
+ const bridgeDiagnoseNavmeshRequestSchema = z.object({
11270
+ includePlayerStarts: z.boolean().default(true),
11271
+ maxIslands: z.number().int().min(1).max(64).default(16),
11272
+ navMeshActorPath: actorPathSchema.optional(),
11273
+ requestId: requestIdSchema,
11274
+ spawnActorPaths: z.array(actorPathSchema).max(64).default([]),
11275
+ type: z.literal(BRIDGE_DIAGNOSE_NAVMESH_REQUEST_TYPE),
11276
+ version: z.literal(2)
11277
+ });
11278
+ const navDiagnosticIslandSchema = z.object({
11279
+ area: z.number().min(0),
11280
+ bounds: z.object({
11281
+ max: navPointSchema,
11282
+ min: navPointSchema
11283
+ }),
11284
+ index: z.number().int().min(0),
11285
+ polyCount: z.number().int().min(0),
11286
+ spawnPointCount: z.number().int().min(0)
11287
+ });
11288
+ const navDiagnosticSpawnPointSchema = z.object({
11289
+ actorPath: z.string(),
11290
+ error: z.string().optional(),
11291
+ islandIndex: z.number().int().min(0).optional(),
11292
+ kind: z.enum(BRIDGE_NAV_SPAWN_POINT_KINDS),
11293
+ location: navPointSchema,
11294
+ onNavMesh: z.boolean(),
11295
+ pathLength: z.number().optional(),
11296
+ projectedLocation: navPointSchema.optional(),
11297
+ reachableFromAnchor: z.boolean(),
11298
+ returnsToAnchor: z.boolean()
11299
+ });
11300
+ const navDiagnosticIssueSchema = z.object({
11301
+ actorPath: z.string().optional(),
11302
+ code: z.enum(BRIDGE_NAV_DIAGNOSTIC_ISSUE_CODES),
11303
+ islandIndex: z.number().int().min(0).optional(),
11304
+ message: z.string()
11305
+ });
11306
+ const bridgeDiagnoseNavmeshSuccessResponseSchema = z.object({
11307
+ anchorActorPath: z.string().optional(),
11308
+ healthy: z.boolean(),
11309
+ islandCount: z.number().int().min(0),
11310
+ islands: z.array(navDiagnosticIslandSchema).max(64),
11311
+ islandsTruncated: z.boolean(),
11312
+ issueCount: z.number().int().min(0),
11313
+ issues: z.array(navDiagnosticIssueSchema).max(64),
11314
+ issuesTruncated: z.boolean(),
11315
+ message: nonEmptyStringSchema.optional(),
11316
+ navBoundsVolumeCount: z.number().int().min(0),
11317
+ navMeshActorPath: z.string(),
11318
+ ok: z.literal(true),
11319
+ polyCount: z.number().int().min(0),
11320
+ requestId: requestIdSchema,
11321
+ spawnPointCount: z.number().int().min(0),
11322
+ spawnPoints: z.array(navDiagnosticSpawnPointSchema).max(64),
11323
+ spawnPointsTruncated: z.boolean(),
11324
+ state: navQueryStateSchema,
11325
+ type: z.literal(BRIDGE_DIAGNOSE_NAVMESH_REQUEST_TYPE),
11326
+ version: z.literal(2)
11327
+ });
11328
+ const bridgeDiagnoseNavmeshResponseSchema = z.union([bridgeDiagnoseNavmeshSuccessResponseSchema, bridgeErrorResponseSchema]);
11329
+ function createBridgeDiagnoseNavmeshRequest(options = {}, requestId = randomUUID()) {
11330
+ return bridgeDiagnoseNavmeshRequestSchema.parse({
11331
+ includePlayerStarts: options.includePlayerStarts,
11332
+ maxIslands: options.maxIslands,
11333
+ navMeshActorPath: options.navMeshActorPath,
11334
+ requestId,
11335
+ spawnActorPaths: options.spawnActorPaths,
11336
+ type: BRIDGE_DIAGNOSE_NAVMESH_REQUEST_TYPE,
11337
+ version: 2
11338
+ });
11339
+ }
11340
+ //#endregion
11341
+ //#region src/protocol/smartObjects.ts
11342
+ const BRIDGE_CREATE_SMART_OBJECT_DEFINITION_REQUEST_TYPE = "create_smart_object_definition";
11343
+ const BRIDGE_GET_SMART_OBJECT_DEFINITION_REQUEST_TYPE = "get_smart_object_definition";
11344
+ const BRIDGE_ADD_SMART_OBJECT_COMPONENT_REQUEST_TYPE = "add_smart_object_component";
11345
+ const BRIDGE_SMART_OBJECT_COMPONENT_TARGETS = ["blueprint", "actor"];
11346
+ const bridgeSmartObjectBehaviorDefinitionSchema = z.object({
11347
+ behaviorClass: assetPathSchema,
11348
+ params: instancedObjectParamsSchema
11349
+ });
11350
+ const activityTagsSchema = z.array(gameplayTagNameSchema).max(16).default([]);
11351
+ const behaviorDefinitionsSchema = z.array(bridgeSmartObjectBehaviorDefinitionSchema).max(8).default([]);
11352
+ const bridgeSmartObjectSlotSchema = z.object({
11353
+ activityTags: activityTagsSchema,
11354
+ behaviorDefinitions: behaviorDefinitionsSchema,
11355
+ enabled: z.boolean().default(true),
11356
+ name: requiredBoundedStringSchema.optional(),
11357
+ offset: bridgeVectorSchema.optional(),
11358
+ rotation: bridgeRotatorSchema.optional()
11359
+ });
11360
+ const bridgeCreateSmartObjectDefinitionRequestSchema = z.object({
11361
+ activityTags: activityTagsSchema,
11362
+ assetName: assetNameSchema,
11363
+ defaultBehaviorDefinitions: behaviorDefinitionsSchema,
11364
+ packagePath: contentPathSchema,
11365
+ requestId: requestIdSchema,
11366
+ slots: z.array(bridgeSmartObjectSlotSchema).min(1).max(32),
11367
+ type: z.literal(BRIDGE_CREATE_SMART_OBJECT_DEFINITION_REQUEST_TYPE),
11368
+ version: z.literal(2)
11369
+ });
11370
+ const bridgeGetSmartObjectDefinitionRequestSchema = z.object({
11371
+ assetPath: assetPathSchema,
11372
+ requestId: requestIdSchema,
11373
+ type: z.literal(BRIDGE_GET_SMART_OBJECT_DEFINITION_REQUEST_TYPE),
11374
+ version: z.literal(2)
11375
+ });
11376
+ const bridgeAddSmartObjectComponentRequestFieldsSchema = z.object({
11377
+ actorPath: actorPathSchema.optional(),
11378
+ blueprintPath: assetPathSchema.optional(),
11379
+ componentName: requiredBoundedStringSchema.optional(),
11380
+ definitionPath: assetPathSchema,
11381
+ requestId: requestIdSchema,
11382
+ type: z.literal(BRIDGE_ADD_SMART_OBJECT_COMPONENT_REQUEST_TYPE),
11383
+ version: z.literal(2)
11384
+ });
11385
+ const bridgeAddSmartObjectComponentRequestSchema = bridgeAddSmartObjectComponentRequestFieldsSchema.refine((request) => request.actorPath === void 0 !== (request.blueprintPath === void 0), {
11386
+ message: "An add_smart_object_component request names exactly one of blueprintPath or actorPath.",
11387
+ path: ["blueprintPath"]
11388
+ });
11389
+ const bridgeSmartObjectSlotReportSchema = z.object({
11390
+ activityTags: z.array(z.string()),
11391
+ behaviorDefinitions: z.array(z.string()),
11392
+ enabled: z.boolean(),
11393
+ index: z.number().int().min(0),
11394
+ name: z.string(),
11395
+ offset: bridgeVectorSchema,
11396
+ rotation: bridgeRotatorSchema
11397
+ });
11398
+ const smartObjectDefinitionReportFields = {
11399
+ activityTags: z.array(z.string()),
11400
+ defaultBehaviorDefinitions: z.array(z.string()),
11401
+ slots: z.array(bridgeSmartObjectSlotReportSchema),
11402
+ valid: z.boolean(),
11403
+ validationMessages: z.array(z.string()).max(32)
11404
+ };
11405
+ const bridgeCreateSmartObjectDefinitionSuccessResponseSchema = z.object({
11406
+ ...createdUserAssetResponseFields,
11407
+ ...smartObjectDefinitionReportFields,
11408
+ type: z.literal(BRIDGE_CREATE_SMART_OBJECT_DEFINITION_REQUEST_TYPE)
11409
+ });
11410
+ const bridgeGetSmartObjectDefinitionSuccessResponseSchema = z.object({
11411
+ ...smartObjectDefinitionReportFields,
11412
+ assetPath: z.string(),
11413
+ message: nonEmptyStringSchema.optional(),
11414
+ ok: z.literal(true),
11415
+ requestId: requestIdSchema,
11416
+ state: aiReportStateSchema,
11417
+ type: z.literal(BRIDGE_GET_SMART_OBJECT_DEFINITION_REQUEST_TYPE),
11418
+ version: z.literal(2)
11419
+ });
11420
+ const bridgeAddSmartObjectComponentSuccessResponseSchema = z.object({
11421
+ componentName: z.string(),
11422
+ created: z.boolean(),
11423
+ definitionPath: z.string(),
11424
+ definitionValid: z.boolean(),
11425
+ message: nonEmptyStringSchema.optional(),
11426
+ ok: z.literal(true),
11427
+ packageDirty: z.boolean(),
11428
+ requestId: requestIdSchema,
11429
+ state: creativeEditStateSchema,
11430
+ target: z.enum(BRIDGE_SMART_OBJECT_COMPONENT_TARGETS),
11431
+ targetPath: z.string(),
11432
+ type: z.literal(BRIDGE_ADD_SMART_OBJECT_COMPONENT_REQUEST_TYPE),
11433
+ version: z.literal(2)
11434
+ });
11435
+ const bridgeCreateSmartObjectDefinitionResponseSchema = z.union([bridgeCreateSmartObjectDefinitionSuccessResponseSchema, bridgeErrorResponseSchema]);
11436
+ const bridgeGetSmartObjectDefinitionResponseSchema = z.union([bridgeGetSmartObjectDefinitionSuccessResponseSchema, bridgeErrorResponseSchema]);
11437
+ const bridgeAddSmartObjectComponentResponseSchema = z.union([bridgeAddSmartObjectComponentSuccessResponseSchema, bridgeErrorResponseSchema]);
11438
+ function createBridgeCreateSmartObjectDefinitionRequest(assetName, packagePath, slots, options = {}, requestId = randomUUID()) {
11439
+ return bridgeCreateSmartObjectDefinitionRequestSchema.parse({
11440
+ activityTags: options.activityTags,
11441
+ assetName,
11442
+ defaultBehaviorDefinitions: options.defaultBehaviorDefinitions,
11443
+ packagePath,
11444
+ requestId,
11445
+ slots,
11446
+ type: BRIDGE_CREATE_SMART_OBJECT_DEFINITION_REQUEST_TYPE,
11447
+ version: 2
11448
+ });
11449
+ }
11450
+ function createBridgeGetSmartObjectDefinitionRequest(assetPath, requestId = randomUUID()) {
11451
+ return bridgeGetSmartObjectDefinitionRequestSchema.parse({
11452
+ assetPath,
11453
+ requestId,
11454
+ type: BRIDGE_GET_SMART_OBJECT_DEFINITION_REQUEST_TYPE,
11455
+ version: 2
11456
+ });
11457
+ }
11458
+ function createBridgeAddSmartObjectComponentRequest(definitionPath, target, options = {}, requestId = randomUUID()) {
11459
+ return bridgeAddSmartObjectComponentRequestSchema.parse({
11460
+ actorPath: target.actorPath,
11461
+ blueprintPath: target.blueprintPath,
11462
+ componentName: options.componentName,
11463
+ definitionPath,
11464
+ requestId,
11465
+ type: BRIDGE_ADD_SMART_OBJECT_COMPONENT_REQUEST_TYPE,
11466
+ version: 2
11467
+ });
11468
+ }
11469
+ //#endregion
11470
+ //#region src/protocol/mass.ts
11471
+ const BRIDGE_CREATE_MASS_ENTITY_CONFIG_REQUEST_TYPE = "create_mass_entity_config";
11472
+ const BRIDGE_EDIT_MASS_ENTITY_CONFIG_REQUEST_TYPE = "edit_mass_entity_config";
11473
+ const BRIDGE_GET_MASS_ENTITY_CONFIG_REQUEST_TYPE = "get_mass_entity_config";
11474
+ const BRIDGE_VALIDATE_MASS_ENTITY_CONFIG_REQUEST_TYPE = "validate_mass_entity_config";
11475
+ const BRIDGE_MASS_TRAIT_OPERATIONS = [
11476
+ "add",
11477
+ "remove",
11478
+ "set"
11479
+ ];
11480
+ const BRIDGE_MASS_READ_STATES = ["reported", "unsupported"];
11481
+ const BRIDGE_MASS_VALIDATION_SEVERITIES = ["error", "warning"];
11482
+ const massReadStateSchema = z.enum(BRIDGE_MASS_READ_STATES);
11483
+ const traitClassSchema = z.string().trim().min(1).max(512);
11484
+ const bridgeMassTraitEditSchema = z.object({
11485
+ operation: z.enum(BRIDGE_MASS_TRAIT_OPERATIONS),
11486
+ properties: z.array(bridgeAssetPropertyEntrySchema).max(32).optional(),
11487
+ traitClass: traitClassSchema
11488
+ }).superRefine((edit, context) => {
11489
+ const count = edit.properties?.length ?? 0;
11490
+ if (edit.operation === "set" && count === 0) context.addIssue({
11491
+ code: z.ZodIssueCode.custom,
11492
+ message: "A 'set' trait edit must carry at least one property.",
11493
+ path: ["properties"]
11494
+ });
11495
+ if (edit.operation === "remove" && count > 0) context.addIssue({
11496
+ code: z.ZodIssueCode.custom,
11497
+ message: "A 'remove' trait edit cannot carry properties.",
11498
+ path: ["properties"]
11499
+ });
11500
+ });
11501
+ const bridgeCreateMassEntityConfigRequestSchema = z.object({
11502
+ assetName: assetNameSchema,
11503
+ packagePath: contentPathSchema,
11504
+ parentConfigPath: assetPathSchema.optional(),
11505
+ requestId: requestIdSchema,
11506
+ type: z.literal(BRIDGE_CREATE_MASS_ENTITY_CONFIG_REQUEST_TYPE),
11507
+ version: z.literal(2)
11508
+ });
11509
+ const bridgeEditMassEntityConfigRequestSchema = z.object({
11510
+ assetPath: assetPathSchema,
11511
+ edits: z.array(bridgeMassTraitEditSchema).min(1).max(16),
11512
+ requestId: requestIdSchema,
11513
+ type: z.literal(BRIDGE_EDIT_MASS_ENTITY_CONFIG_REQUEST_TYPE),
11514
+ version: z.literal(2)
11515
+ });
11516
+ const bridgeGetMassEntityConfigRequestSchema = z.object({
11517
+ assetPath: assetPathSchema,
11518
+ requestId: requestIdSchema,
11519
+ type: z.literal(BRIDGE_GET_MASS_ENTITY_CONFIG_REQUEST_TYPE),
11520
+ version: z.literal(2)
11521
+ });
11522
+ const bridgeValidateMassEntityConfigRequestSchema = z.object({
11523
+ assetPath: assetPathSchema,
11524
+ requestId: requestIdSchema,
11525
+ type: z.literal(BRIDGE_VALIDATE_MASS_ENTITY_CONFIG_REQUEST_TYPE),
11526
+ version: z.literal(2)
11527
+ });
11528
+ const bridgeCreateMassEntityConfigSuccessResponseSchema = z.object({
11529
+ ...createdUserAssetResponseFields,
11530
+ parentConfigPath: z.string().optional(),
11531
+ type: z.literal(BRIDGE_CREATE_MASS_ENTITY_CONFIG_REQUEST_TYPE)
11532
+ });
11533
+ const bridgeEditMassEntityConfigSuccessResponseSchema = z.object({
11534
+ ...authoringBatchResponseFields,
11535
+ traits: z.array(z.string()).max(64),
11536
+ type: z.literal(BRIDGE_EDIT_MASS_ENTITY_CONFIG_REQUEST_TYPE)
11537
+ });
11538
+ const bridgeMassTraitReportSchema = z.object({
11539
+ index: z.number().int().min(0),
11540
+ properties: z.record(z.string(), z.string()),
11541
+ traitClass: z.string(),
11542
+ traitName: z.string()
11543
+ });
11544
+ const bridgeGetMassEntityConfigSuccessResponseSchema = z.object({
11545
+ assetPath: z.string(),
11546
+ message: nonEmptyStringSchema.optional(),
11547
+ ok: z.literal(true),
11548
+ parentConfigPath: z.string().optional(),
11549
+ requestId: requestIdSchema,
11550
+ state: massReadStateSchema,
11551
+ traits: z.array(bridgeMassTraitReportSchema).max(64),
11552
+ truncated: z.boolean(),
11553
+ type: z.literal(BRIDGE_GET_MASS_ENTITY_CONFIG_REQUEST_TYPE),
11554
+ version: z.literal(2)
11555
+ });
11556
+ const bridgeMassValidationMessageSchema = z.object({
11557
+ category: z.string(),
11558
+ severity: z.enum(BRIDGE_MASS_VALIDATION_SEVERITIES),
11559
+ text: z.string()
11560
+ });
11561
+ const bridgeValidateMassEntityConfigSuccessResponseSchema = z.object({
11562
+ assetPath: z.string(),
11563
+ errorCount: z.number().int().min(0),
11564
+ message: nonEmptyStringSchema.optional(),
11565
+ messages: z.array(bridgeMassValidationMessageSchema).max(32),
11566
+ ok: z.literal(true),
11567
+ requestId: requestIdSchema,
11568
+ state: massReadStateSchema,
11569
+ truncated: z.boolean(),
11570
+ type: z.literal(BRIDGE_VALIDATE_MASS_ENTITY_CONFIG_REQUEST_TYPE),
11571
+ valid: z.boolean(),
11572
+ version: z.literal(2),
11573
+ warningCount: z.number().int().min(0)
11574
+ });
11575
+ const bridgeCreateMassEntityConfigResponseSchema = z.union([bridgeCreateMassEntityConfigSuccessResponseSchema, bridgeErrorResponseSchema]);
11576
+ const bridgeEditMassEntityConfigResponseSchema = z.union([bridgeEditMassEntityConfigSuccessResponseSchema, bridgeErrorResponseSchema]);
11577
+ const bridgeGetMassEntityConfigResponseSchema = z.union([bridgeGetMassEntityConfigSuccessResponseSchema, bridgeErrorResponseSchema]);
11578
+ const bridgeValidateMassEntityConfigResponseSchema = z.union([bridgeValidateMassEntityConfigSuccessResponseSchema, bridgeErrorResponseSchema]);
11579
+ function createBridgeCreateMassEntityConfigRequest(assetName, packagePath, options = {}, requestId = randomUUID()) {
11580
+ return bridgeCreateMassEntityConfigRequestSchema.parse({
11581
+ assetName,
11582
+ packagePath,
11583
+ parentConfigPath: options.parentConfigPath,
11584
+ requestId,
11585
+ type: BRIDGE_CREATE_MASS_ENTITY_CONFIG_REQUEST_TYPE,
11586
+ version: 2
11587
+ });
11588
+ }
11589
+ function createBridgeEditMassEntityConfigRequest(assetPath, edits, requestId = randomUUID()) {
11590
+ return bridgeEditMassEntityConfigRequestSchema.parse({
11591
+ assetPath,
11592
+ edits,
11593
+ requestId,
11594
+ type: BRIDGE_EDIT_MASS_ENTITY_CONFIG_REQUEST_TYPE,
11595
+ version: 2
11596
+ });
11597
+ }
11598
+ function createBridgeGetMassEntityConfigRequest(assetPath, requestId = randomUUID()) {
11599
+ return bridgeGetMassEntityConfigRequestSchema.parse({
11600
+ assetPath,
11601
+ requestId,
11602
+ type: BRIDGE_GET_MASS_ENTITY_CONFIG_REQUEST_TYPE,
11603
+ version: 2
11604
+ });
11605
+ }
11606
+ function createBridgeValidateMassEntityConfigRequest(assetPath, requestId = randomUUID()) {
11607
+ return bridgeValidateMassEntityConfigRequestSchema.parse({
11608
+ assetPath,
11609
+ requestId,
11610
+ type: BRIDGE_VALIDATE_MASS_ENTITY_CONFIG_REQUEST_TYPE,
11611
+ version: 2
11612
+ });
11613
+ }
11018
11614
  //#endregion
11019
11615
  //#region src/version.ts
11020
- const SERVER_VERSION = "1.11.0";
11616
+ const SERVER_VERSION = "1.12.1";
11021
11617
  //#endregion
11022
11618
  //#region src/bridgeSocketClient.ts
11023
11619
  var BridgeSocketError = class extends Error {
@@ -11253,6 +11849,9 @@ async function sendBridgeSetPinDefaultRequest(request, options) {
11253
11849
  async function sendBridgeListAvailableNodesRequest(request, options) {
11254
11850
  return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeListAvailableNodesResponseSchema, request.requestId);
11255
11851
  }
11852
+ async function sendBridgeLayoutGraphRequest(request, options) {
11853
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeLayoutGraphResponseSchema, request.requestId);
11854
+ }
11256
11855
  async function sendBridgeSetViewportCameraRequest(request, options) {
11257
11856
  return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeSetViewportCameraResponseSchema, request.requestId);
11258
11857
  }
@@ -11973,6 +12572,36 @@ async function sendBridgeFindPathRequest(request, options) {
11973
12572
  async function sendBridgeTestReachabilityRequest(request, options) {
11974
12573
  return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeTestReachabilityResponseSchema, request.requestId);
11975
12574
  }
12575
+ async function sendBridgeCreateSmartObjectDefinitionRequest(request, options) {
12576
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeCreateSmartObjectDefinitionResponseSchema, request.requestId);
12577
+ }
12578
+ async function sendBridgeGetSmartObjectDefinitionRequest(request, options) {
12579
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeGetSmartObjectDefinitionResponseSchema, request.requestId);
12580
+ }
12581
+ async function sendBridgeAddSmartObjectComponentRequest(request, options) {
12582
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeAddSmartObjectComponentResponseSchema, request.requestId);
12583
+ }
12584
+ async function sendBridgeCreateMassEntityConfigRequest(request, options) {
12585
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeCreateMassEntityConfigResponseSchema, request.requestId);
12586
+ }
12587
+ async function sendBridgeEditMassEntityConfigRequest(request, options) {
12588
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeEditMassEntityConfigResponseSchema, request.requestId);
12589
+ }
12590
+ async function sendBridgeGetMassEntityConfigRequest(request, options) {
12591
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeGetMassEntityConfigResponseSchema, request.requestId);
12592
+ }
12593
+ async function sendBridgeValidateMassEntityConfigRequest(request, options) {
12594
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeValidateMassEntityConfigResponseSchema, request.requestId);
12595
+ }
12596
+ async function sendBridgeDiagnoseNavmeshRequest(request, options) {
12597
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeDiagnoseNavmeshResponseSchema, request.requestId);
12598
+ }
12599
+ async function sendBridgeUpdateStateTreeElementsRequest(request, options) {
12600
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeUpdateStateTreeElementsResponseSchema, request.requestId);
12601
+ }
12602
+ async function sendBridgeRemoveStateTreeElementsRequest(request, options) {
12603
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeRemoveStateTreeElementsResponseSchema, request.requestId);
12604
+ }
11976
12605
  //#endregion
11977
12606
  //#region src/enginePing.ts
11978
12607
  async function pingRegistryEntry$1(entry, options) {
@@ -18799,6 +19428,7 @@ const debuggerToolDomain = {
18799
19428
  };
18800
19429
  //#endregion
18801
19430
  //#region src/traceAnalysis.ts
19431
+ const LLM_TAG_COUNTER_PATTERN = "STAT_*LLM";
18802
19432
  const SECONDS_TO_MS = 1e3;
18803
19433
  const FRAME_ROOT_TIMER_NAMES = /* @__PURE__ */ new Set(["FEngineLoop::Tick"]);
18804
19434
  function parseCsvRows(text) {
@@ -18891,6 +19521,9 @@ function summarizeTimerStatistics(rows, maxScopes) {
18891
19521
  if (count !== void 0) scope.count = count;
18892
19522
  scopes.push(scope);
18893
19523
  }
19524
+ return rankScopes(scopes, maxScopes);
19525
+ }
19526
+ function rankScopes(scopes, maxScopes) {
18894
19527
  const byInclusiveTime = [...scopes].sort((left, right) => right.inclusiveTimeMs - left.inclusiveTimeMs);
18895
19528
  return {
18896
19529
  byExclusiveTime: [...scopes].sort((left, right) => right.exclusiveTimeMs - left.exclusiveTimeMs).slice(0, maxScopes),
@@ -18902,18 +19535,20 @@ function summarizeTimerStatistics(rows, maxScopes) {
18902
19535
  function isGpuThread(threadName) {
18903
19536
  return threadName.toUpperCase().includes("GPU");
18904
19537
  }
18905
- async function summarizeTimingEventStream(lines, options) {
19538
+ async function forEachTimingEvent(lines, visit) {
18906
19539
  let headers;
18907
19540
  let threadIndex = -1;
18908
19541
  let timerIndex = -1;
18909
19542
  let durationIndex = -1;
18910
19543
  let startIndex = -1;
18911
19544
  let depthIndex = -1;
18912
- let cpuTimeMs = 0;
18913
- let gpuTimeMs = 0;
18914
- const frameDurationsMs = [];
18915
- const worstHitches = [];
18916
- let hitchCount = 0;
19545
+ const event = {
19546
+ depth: 0,
19547
+ durationMs: 0,
19548
+ startTimeMs: 0,
19549
+ threadName: "",
19550
+ timerName: ""
19551
+ };
18917
19552
  for await (const rawLine of lines) {
18918
19553
  const line = rawLine.trim();
18919
19554
  if (line.length === 0) continue;
@@ -18926,36 +19561,160 @@ async function summarizeTimingEventStream(lines, options) {
18926
19561
  durationIndex = columnIndex(headers, findColumn(headerRow, "Duration", "InclusiveTime"));
18927
19562
  startIndex = columnIndex(headers, findColumn(headerRow, "StartTime", "Start"));
18928
19563
  depthIndex = columnIndex(headers, findColumn(headerRow, "Depth"));
18929
- if (threadIndex < 0 || durationIndex < 0) break;
19564
+ if (threadIndex < 0 || durationIndex < 0) return;
18930
19565
  continue;
18931
19566
  }
18932
19567
  const duration = readNumber(values[durationIndex]);
18933
19568
  const threadName = values[threadIndex];
18934
19569
  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;
19570
+ event.depth = depthIndex < 0 ? 0 : readNumber(values[depthIndex]) ?? 0;
19571
+ event.durationMs = duration * SECONDS_TO_MS;
19572
+ event.startTimeMs = (startIndex < 0 ? 0 : readNumber(values[startIndex]) ?? 0) * SECONDS_TO_MS;
19573
+ event.threadName = threadName;
19574
+ event.timerName = timerIndex < 0 ? "" : values[timerIndex] ?? "";
19575
+ visit(event);
19576
+ }
19577
+ }
19578
+ var ScopeAncestry = class {
19579
+ names = [];
19580
+ threadName;
19581
+ enter(event) {
19582
+ if (event.threadName !== this.threadName) {
19583
+ this.threadName = event.threadName;
19584
+ this.names.length = 0;
18940
19585
  }
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;
19586
+ this.names.length = Math.min(this.names.length, event.depth);
19587
+ const parentName = event.depth > 0 ? this.names[event.depth - 1] : void 0;
19588
+ this.names[event.depth] = event.timerName;
19589
+ return parentName;
19590
+ }
19591
+ hasOpenAncestorNamed(event) {
19592
+ return this.names.slice(0, event.depth).includes(event.timerName);
19593
+ }
19594
+ };
19595
+ async function summarizeTimingEventStream(lines, options) {
19596
+ let cpuTimeMs = 0;
19597
+ let gpuTimeMs = 0;
19598
+ const frameDurationsMs = [];
19599
+ const worstHitches = [];
19600
+ let hitchCount = 0;
19601
+ const gpuScopeTotals = /* @__PURE__ */ new Map();
19602
+ const gpuAncestry = new ScopeAncestry();
19603
+ await forEachTimingEvent(lines, (event) => {
19604
+ if (isGpuThread(event.threadName)) {
19605
+ accumulateGpuScope(gpuScopeTotals, gpuAncestry, event);
19606
+ if (event.depth === 0) gpuTimeMs += event.durationMs;
19607
+ return;
19608
+ }
19609
+ if (event.depth !== 0) return;
19610
+ cpuTimeMs += event.durationMs;
19611
+ if (!FRAME_ROOT_TIMER_NAMES.has(event.timerName)) return;
19612
+ frameDurationsMs.push(event.durationMs);
19613
+ if (event.durationMs < options.hitchThresholdMs) return;
18945
19614
  hitchCount += 1;
18946
19615
  retainWorstHitch(worstHitches, options.maxHitches, {
18947
- durationMs,
18948
- startTimeMs: (startIndex < 0 ? 0 : readNumber(values[startIndex]) ?? 0) * SECONDS_TO_MS
19616
+ durationMs: event.durationMs,
19617
+ startTimeMs: event.startTimeMs,
19618
+ topScopes: []
18949
19619
  });
18950
- }
19620
+ });
18951
19621
  return {
18952
19622
  frames: summarizeFrameDurations(frameDurationsMs, worstHitches, hitchCount, options),
19623
+ gpuScopes: rankScopeTotals(gpuScopeTotals, options.maxScopes),
18953
19624
  threads: {
18954
19625
  cpuTimeMs,
18955
19626
  gpuTimeMs
18956
19627
  }
18957
19628
  };
18958
19629
  }
19630
+ function accumulateGpuScope(totals, ancestry, event) {
19631
+ const parentName = ancestry.enter(event);
19632
+ const scope = scopeTotalsFor(totals, event.timerName);
19633
+ scope.count += 1;
19634
+ scope.exclusiveTimeMs += event.durationMs;
19635
+ if (!ancestry.hasOpenAncestorNamed(event)) scope.inclusiveTimeMs += event.durationMs;
19636
+ if (parentName !== void 0) scopeTotalsFor(totals, parentName).exclusiveTimeMs -= event.durationMs;
19637
+ }
19638
+ function scopeTotalsFor(totals, name) {
19639
+ const existing = totals.get(name);
19640
+ if (existing !== void 0) return existing;
19641
+ const created = {
19642
+ count: 0,
19643
+ exclusiveTimeMs: 0,
19644
+ inclusiveTimeMs: 0
19645
+ };
19646
+ totals.set(name, created);
19647
+ return created;
19648
+ }
19649
+ function rankScopeTotals(totals, maxScopes) {
19650
+ return rankScopes([...totals].map(([name, scope]) => ({
19651
+ count: scope.count,
19652
+ exclusiveTimeMs: scope.exclusiveTimeMs,
19653
+ inclusiveTimeMs: scope.inclusiveTimeMs,
19654
+ name
19655
+ })), maxScopes);
19656
+ }
19657
+ const SCOPE_KEY_SEPARATOR = "\0";
19658
+ const IDLE_TIMER_NAMES = /* @__PURE__ */ new Set(["TaskWorkerIsLookingForWork", "WaitForTasks"]);
19659
+ async function attributeHitchScopes(lines, hitches, maxScopesPerHitch) {
19660
+ if (hitches.length === 0) return [];
19661
+ const windows = hitches.map((hitch) => ({
19662
+ endTimeMs: hitch.startTimeMs + hitch.durationMs,
19663
+ exclusiveByScope: /* @__PURE__ */ new Map(),
19664
+ hitch,
19665
+ startTimeMs: hitch.startTimeMs
19666
+ })).sort((left, right) => left.startTimeMs - right.startTimeMs);
19667
+ const ancestry = new ScopeAncestry();
19668
+ await forEachTimingEvent(lines, (event) => {
19669
+ if (isGpuThread(event.threadName)) return;
19670
+ const parentName = ancestry.enter(event);
19671
+ const eventEndMs = event.startTimeMs + event.durationMs;
19672
+ for (let index = firstWindowEndingAfter(windows, event.startTimeMs); index < windows.length && (windows[index]?.startTimeMs ?? Number.POSITIVE_INFINITY) < eventEndMs; index += 1) {
19673
+ const window = windows[index];
19674
+ if (window === void 0) break;
19675
+ const overlapMs = Math.min(eventEndMs, window.endTimeMs) - Math.max(event.startTimeMs, window.startTimeMs);
19676
+ if (overlapMs <= 0) continue;
19677
+ addScopeTime(window.exclusiveByScope, event.threadName, event.timerName, overlapMs);
19678
+ if (parentName !== void 0) addScopeTime(window.exclusiveByScope, event.threadName, parentName, -overlapMs);
19679
+ }
19680
+ });
19681
+ return hitches.map((hitch) => {
19682
+ const window = windows.find((candidate) => candidate.hitch === hitch);
19683
+ return {
19684
+ ...hitch,
19685
+ topScopes: window === void 0 ? [] : topHitchScopes(window, maxScopesPerHitch)
19686
+ };
19687
+ });
19688
+ }
19689
+ function firstWindowEndingAfter(windows, timeMs) {
19690
+ let low = 0;
19691
+ let high = windows.length;
19692
+ while (low < high) {
19693
+ const middle = low + high >>> 1;
19694
+ if ((windows[middle]?.endTimeMs ?? Number.POSITIVE_INFINITY) <= timeMs) low = middle + 1;
19695
+ else high = middle;
19696
+ }
19697
+ return low;
19698
+ }
19699
+ function addScopeTime(exclusiveByScope, threadName, timerName, ms) {
19700
+ const key = `${threadName}${SCOPE_KEY_SEPARATOR}${timerName}`;
19701
+ exclusiveByScope.set(key, (exclusiveByScope.get(key) ?? 0) + ms);
19702
+ }
19703
+ function topHitchScopes(window, maxScopes) {
19704
+ const scopes = [];
19705
+ for (const [key, exclusiveTimeMs] of window.exclusiveByScope) {
19706
+ if (exclusiveTimeMs <= 1e-6) continue;
19707
+ const separatorAt = key.indexOf(SCOPE_KEY_SEPARATOR);
19708
+ const name = key.slice(separatorAt + 1);
19709
+ if (IDLE_TIMER_NAMES.has(name)) continue;
19710
+ scopes.push({
19711
+ exclusiveTimeMs,
19712
+ name,
19713
+ threadName: key.slice(0, separatorAt)
19714
+ });
19715
+ }
19716
+ return scopes.sort((left, right) => right.exclusiveTimeMs - left.exclusiveTimeMs).slice(0, maxScopes);
19717
+ }
18959
19718
  function retainWorstHitch(worstHitches, maxHitches, hitch) {
18960
19719
  if (worstHitches.length >= maxHitches) {
18961
19720
  const weakest = worstHitches[worstHitches.length - 1];
@@ -18991,16 +19750,53 @@ function percentile(sortedValues, fraction) {
18991
19750
  if (sortedValues.length === 0) return 0;
18992
19751
  return sortedValues[Math.min(sortedValues.length - 1, Math.max(0, Math.ceil(fraction * sortedValues.length) - 1))] ?? 0;
18993
19752
  }
19753
+ function llmTagNameFromCounter(counterName) {
19754
+ return counterName.replace(/^STAT_/u, "").replace(/LLM$/u, "");
19755
+ }
19756
+ async function summarizeMemoryTagCounter(name, lines) {
19757
+ let valueIndex = -1;
19758
+ let finalBytes;
19759
+ let peakBytes = Number.NEGATIVE_INFINITY;
19760
+ let sawHeader = false;
19761
+ for await (const rawLine of lines) {
19762
+ const line = rawLine.trim();
19763
+ if (line.length === 0) continue;
19764
+ const values = parseCsvLine(line);
19765
+ if (!sawHeader) {
19766
+ sawHeader = true;
19767
+ valueIndex = values.findIndex((header) => header.toLowerCase() === "value");
19768
+ if (valueIndex < 0) return;
19769
+ continue;
19770
+ }
19771
+ const value = readNumber(values[valueIndex]);
19772
+ if (value === void 0) continue;
19773
+ finalBytes = value;
19774
+ peakBytes = Math.max(peakBytes, value);
19775
+ }
19776
+ return finalBytes === void 0 ? void 0 : {
19777
+ finalBytes,
19778
+ name,
19779
+ peakBytes
19780
+ };
19781
+ }
19782
+ function rankMemoryTags(tags, maxTags) {
19783
+ return {
19784
+ tags: [...tags].sort((left, right) => right.peakBytes - left.peakBytes).slice(0, maxTags),
19785
+ totalTagCount: tags.length,
19786
+ truncated: tags.length > maxTags
19787
+ };
19788
+ }
18994
19789
  //#endregion
18995
19790
  //#region src/tools/diagnostics.ts
18996
19791
  const ANALYZE_TRACE_DEFAULT_TIMEOUT_MS = 6e5;
18997
19792
  const ANALYZE_TRACE_DEFAULT_HITCH_THRESHOLD_MS = 33.4;
18998
19793
  const ANALYZE_TRACE_MAX_RESPONSE_BYTES = 32768;
19794
+ const LLM_COUNTER_FILE_PREFIX = "llm-";
18999
19795
  const analyzeTraceInputSchema = {
19000
19796
  engineVersion: engineVersionSchema,
19001
19797
  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
19798
  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)}).`),
19799
+ 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
19800
  projectPath: z.string().trim().min(1).optional().describe("Project whose EngineAssociation selects the analyzer engine. Omit when engineVersion is given."),
19005
19801
  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
19802
  tracePath: z.string().trim().min(1).describe("Path to the .utrace file produced by stop_insights_trace.")
@@ -19016,8 +19812,10 @@ async function analyzeTrace(input, dependencies, context = createEngineToolchain
19016
19812
  engineVersion: engine.engineVersion,
19017
19813
  hitchThresholdMs,
19018
19814
  hitches: [],
19815
+ memoryTags: [],
19019
19816
  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
19817
  state: "unsupported",
19818
+ topGpuScopes: [],
19021
19819
  topScopesByExclusiveTime: [],
19022
19820
  topScopesByInclusiveTime: [],
19023
19821
  tracePath,
@@ -19029,7 +19827,11 @@ async function analyzeTrace(input, dependencies, context = createEngineToolchain
19029
19827
  const timingEventsPath = path.join(exportDirectory, "timing-events.csv");
19030
19828
  const commandFilePath = path.join(exportDirectory, "export.rsp");
19031
19829
  try {
19032
- await context.writeFile(commandFilePath, [`TimingInsights.ExportTimerStatistics ${quoteConsoleArgument(timerStatisticsPath)}`, `TimingInsights.ExportTimingEvents ${quoteConsoleArgument(timingEventsPath)} -columns=ThreadName,TimerName,StartTime,Duration,Depth`].join("\n"));
19830
+ await context.writeFile(commandFilePath, [
19831
+ `TimingInsights.ExportTimerStatistics ${quoteConsoleArgument(timerStatisticsPath)}`,
19832
+ `TimingInsights.ExportTimingEvents ${quoteConsoleArgument(timingEventsPath)} -columns=ThreadName,TimerName,StartTime,Duration,Depth`,
19833
+ `TimingInsights.ExportCounterValues ${quoteConsoleArgument(path.join(exportDirectory, `${LLM_COUNTER_FILE_PREFIX}{counter}.csv`))} -counter=${LLM_TAG_COUNTER_PATTERN}`
19834
+ ].join("\n"));
19033
19835
  dependencies.logger.info({
19034
19836
  engineVersion: engine.engineVersion,
19035
19837
  tracePath
@@ -19049,16 +19851,24 @@ async function analyzeTrace(input, dependencies, context = createEngineToolchain
19049
19851
  });
19050
19852
  if (run.timedOut) throw new EngineToolchainError(`Unreal Insights did not finish analyzing ${tracePath} within ${String(timeoutMs)}ms; raise timeoutMs or trim the trace.`);
19051
19853
  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(), {
19854
+ const maxScopes = input.maxScopes ?? 20;
19855
+ const scopeSummaries = summarizeTimerStatistics(await readCsvRows(timerStatisticsPath, context), maxScopes);
19856
+ const hasTimingEvents = await context.fileExists(timingEventsPath);
19857
+ const readTimingEventLines = () => hasTimingEvents ? context.readTextLines(timingEventsPath) : emptyTextLines();
19858
+ const timingEvents = await summarizeTimingEventStream(readTimingEventLines(), {
19054
19859
  hitchThresholdMs,
19055
- maxHitches: input.maxHitches ?? 10
19860
+ maxHitches: input.maxHitches ?? 10,
19861
+ maxScopes
19056
19862
  });
19057
19863
  const frames = timingEvents.frames;
19058
19864
  const threadTimes = timingEvents.threads;
19865
+ const hitches = await attributeHitchScopes(readTimingEventLines(), frames.hitches, 5);
19866
+ const memoryTags = await summarizeMemoryTags(exportDirectory, maxScopes, context);
19059
19867
  const truncated = [];
19060
19868
  if (scopeSummaries.truncated) truncated.push("topScopes");
19061
19869
  if (frames.hitchesTruncated) truncated.push("hitches");
19870
+ if (timingEvents.gpuScopes.truncated) truncated.push("topGpuScopes");
19871
+ if (memoryTags.truncated) truncated.push("memoryTags");
19062
19872
  const result = {
19063
19873
  analyzerPath,
19064
19874
  cpuTimeMs: threadTimes.cpuTimeMs,
@@ -19068,10 +19878,14 @@ async function analyzeTrace(input, dependencies, context = createEngineToolchain
19068
19878
  frameCount: frames.frameCount,
19069
19879
  gpuTimeMs: threadTimes.gpuTimeMs,
19070
19880
  hitchThresholdMs,
19071
- hitches: frames.hitches,
19881
+ hitches,
19882
+ memoryTags: memoryTags.tags,
19072
19883
  state: "analyzed",
19884
+ topGpuScopes: timingEvents.gpuScopes.byExclusiveTime,
19073
19885
  topScopesByExclusiveTime: scopeSummaries.byExclusiveTime,
19074
19886
  topScopesByInclusiveTime: scopeSummaries.byInclusiveTime,
19887
+ totalGpuScopeCount: timingEvents.gpuScopes.totalScopeCount,
19888
+ totalMemoryTagCount: memoryTags.totalTagCount,
19075
19889
  totalScopeCount: scopeSummaries.totalScopeCount,
19076
19890
  tracePath,
19077
19891
  truncated
@@ -19117,22 +19931,42 @@ function boundAnalyzeTraceResult(result) {
19117
19931
  truncated: [...result.truncated]
19118
19932
  };
19119
19933
  while (JSON.stringify(bounded).length > ANALYZE_TRACE_MAX_RESPONSE_BYTES) {
19120
- const longestListLength = Math.max(bounded.topScopesByInclusiveTime.length, bounded.topScopesByExclusiveTime.length, bounded.hitches.length);
19934
+ const topScopesLength = Math.max(bounded.topScopesByInclusiveTime.length, bounded.topScopesByExclusiveTime.length);
19935
+ const longestListLength = Math.max(topScopesLength, bounded.hitches.length, bounded.topGpuScopes.length, bounded.memoryTags.length);
19121
19936
  if (longestListLength <= 1) {
19122
19937
  addTruncationReason(bounded, "responseBytesExceeded");
19123
19938
  return bounded;
19124
19939
  }
19125
- if (bounded.topScopesByInclusiveTime.length === longestListLength) {
19940
+ if (topScopesLength === longestListLength) {
19126
19941
  bounded.topScopesByInclusiveTime = bounded.topScopesByInclusiveTime.slice(0, longestListLength - 1);
19127
19942
  bounded.topScopesByExclusiveTime = bounded.topScopesByExclusiveTime.slice(0, longestListLength - 1);
19128
19943
  addTruncationReason(bounded, "topScopes");
19129
19944
  continue;
19130
19945
  }
19946
+ if (bounded.topGpuScopes.length === longestListLength) {
19947
+ bounded.topGpuScopes = bounded.topGpuScopes.slice(0, longestListLength - 1);
19948
+ addTruncationReason(bounded, "topGpuScopes");
19949
+ continue;
19950
+ }
19951
+ if (bounded.memoryTags.length === longestListLength) {
19952
+ bounded.memoryTags = bounded.memoryTags.slice(0, longestListLength - 1);
19953
+ addTruncationReason(bounded, "memoryTags");
19954
+ continue;
19955
+ }
19131
19956
  bounded.hitches = bounded.hitches.slice(0, bounded.hitches.length - 1);
19132
19957
  addTruncationReason(bounded, "hitches");
19133
19958
  }
19134
19959
  return bounded;
19135
19960
  }
19961
+ async function summarizeMemoryTags(exportDirectory, maxTags, context) {
19962
+ const counterFiles = (await context.listDirectory(exportDirectory)).filter((fileName) => fileName.startsWith(LLM_COUNTER_FILE_PREFIX) && fileName.endsWith(".csv"));
19963
+ const tags = [];
19964
+ for (const fileName of counterFiles) {
19965
+ const tag = await summarizeMemoryTagCounter(llmTagNameFromCounter(fileName.slice(4, -4)), context.readTextLines(path.join(exportDirectory, fileName)));
19966
+ if (tag !== void 0) tags.push(tag);
19967
+ }
19968
+ return rankMemoryTags(tags, maxTags);
19969
+ }
19136
19970
  function addTruncationReason(result, reason) {
19137
19971
  if (!result.truncated.includes(reason)) result.truncated.push(reason);
19138
19972
  }
@@ -19270,7 +20104,7 @@ function registerDiagnosticsTools(server, dependencies) {
19270
20104
  }, dependencies));
19271
20105
  });
19272
20106
  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.",
20107
+ 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
20108
  inputSchema: analyzeTraceInputSchema,
19275
20109
  title: "Analyze Trace"
19276
20110
  }, async (input) => {
@@ -20111,6 +20945,7 @@ const listGraphNodesInputSchema = {
20111
20945
  };
20112
20946
  const addGraphNodeInputSchema = {
20113
20947
  assetPath: bridgeAddGraphNodeRequestFieldsSchema.shape.assetPath.describe("Package name or object path of the asset owning the graph."),
20948
+ 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
20949
  graphName: bridgeAddGraphNodeRequestFieldsSchema.shape.graphName.describe("Graph to add the node to."),
20115
20950
  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
20951
  memberName: bridgeAddGraphNodeRequestFieldsSchema.shape.memberName.describe("Function or variable name, required for every kind except 'class'."),
@@ -20152,6 +20987,11 @@ const setPinDefaultInputSchema = {
20152
20987
  projectId: creativeProjectIdSchema,
20153
20988
  value: bridgeSetPinDefaultRequestSchema.shape.value.describe("ExportText value, the same format get_actor_details emits and set_actor_property accepts.")
20154
20989
  };
20990
+ const layoutGraphInputSchema = {
20991
+ assetPath: bridgeLayoutGraphRequestSchema.shape.assetPath.describe("Package name or object path of the Blueprint owning the graph."),
20992
+ graphName: bridgeLayoutGraphRequestSchema.shape.graphName.describe("Graph to arrange, as get_blueprint_summary reports it (e.g. 'EventGraph')."),
20993
+ projectId: creativeProjectIdSchema
20994
+ };
20155
20995
  const listAvailableNodesInputSchema = {
20156
20996
  assetPath: bridgeListAvailableNodesRequestSchema.shape.assetPath.describe("Package name or object path of the asset owning the graph."),
20157
20997
  cursor: bridgeListAvailableNodesRequestSchema.shape.cursor.describe("nextCursor from a previous response, to fetch the following page."),
@@ -20169,6 +21009,7 @@ async function listGraphNodes(input, dependencies) {
20169
21009
  }
20170
21010
  async function addGraphNode(input, dependencies) {
20171
21011
  return await exchangeCreativeRequest(createBridgeAddGraphNodeRequest(input.assetPath, input.graphName, input.kind, {
21012
+ autoLayout: input.autoLayout,
20172
21013
  memberName: input.memberName,
20173
21014
  memberParentClass: input.memberParentClass,
20174
21015
  nodeClass: input.nodeClass,
@@ -20207,6 +21048,9 @@ async function listAvailableNodes(input, dependencies) {
20207
21048
  nameFilter: input.nameFilter
20208
21049
  }), sendBridgeListAvailableNodesRequest, BRIDGE_LIST_AVAILABLE_NODES_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
20209
21050
  }
21051
+ async function layoutGraph(input, dependencies) {
21052
+ return await exchangeCreativeRequest(createBridgeLayoutGraphRequest(input.assetPath, input.graphName), sendBridgeLayoutGraphRequest, BRIDGE_LAYOUT_GRAPH_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
21053
+ }
20210
21054
  function registerGraphTools(server, dependencies) {
20211
21055
  server.registerTool("list_graph_nodes", {
20212
21056
  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 +21067,13 @@ function registerGraphTools(server, dependencies) {
20223
21067
  }, dependencies));
20224
21068
  });
20225
21069
  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.",
21070
+ 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
21071
  inputSchema: addGraphNodeInputSchema,
20228
21072
  title: "Add Graph Node"
20229
- }, async ({ assetPath, graphName, kind, memberName, memberParentClass, nodeClass, pinDefaults, position, projectId }) => {
21073
+ }, async ({ assetPath, autoLayout, graphName, kind, memberName, memberParentClass, nodeClass, pinDefaults, position, projectId }) => {
20230
21074
  return toToolSuccess(await addGraphNode({
20231
21075
  assetPath,
21076
+ autoLayout,
20232
21077
  graphName,
20233
21078
  kind,
20234
21079
  memberName,
@@ -20309,6 +21154,17 @@ function registerGraphTools(server, dependencies) {
20309
21154
  projectId
20310
21155
  }, dependencies));
20311
21156
  });
21157
+ server.registerTool("layout_graph", {
21158
+ 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.",
21159
+ inputSchema: layoutGraphInputSchema,
21160
+ title: "Layout Graph"
21161
+ }, async ({ assetPath, graphName, projectId }) => {
21162
+ return toToolSuccess(await layoutGraph({
21163
+ assetPath,
21164
+ graphName,
21165
+ projectId
21166
+ }, dependencies));
21167
+ });
20312
21168
  }
20313
21169
  const graphToolDomain = {
20314
21170
  domain: "graph",
@@ -20320,7 +21176,8 @@ const graphToolDomain = {
20320
21176
  "connect_pins",
20321
21177
  "disconnect_pins",
20322
21178
  "set_pin_default",
20323
- "list_available_nodes"
21179
+ "list_available_nodes",
21180
+ "layout_graph"
20324
21181
  ]
20325
21182
  };
20326
21183
  //#endregion
@@ -22832,6 +23689,95 @@ const logsToolDomain = {
22832
23689
  ]
22833
23690
  };
22834
23691
  //#endregion
23692
+ //#region src/tools/mass.ts
23693
+ 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.";
23694
+ const createMassEntityConfigInputSchema = {
23695
+ assetName: bridgeCreateMassEntityConfigRequestSchema.shape.assetName.describe("Name of the new MassEntityConfig asset, e.g. 'DA_CrowdAgent'."),
23696
+ packagePath: bridgeCreateMassEntityConfigRequestSchema.shape.packagePath.describe("Content folder to create the config in, e.g. /Game/Mass."),
23697
+ parentConfigPath: bridgeCreateMassEntityConfigRequestSchema.shape.parentConfigPath.describe("Optional MassEntityConfig to inherit traits from; this config overrides any trait of the same class."),
23698
+ projectId: creativeProjectIdSchema
23699
+ };
23700
+ const editMassEntityConfigInputSchema = {
23701
+ assetPath: bridgeEditMassEntityConfigRequestSchema.shape.assetPath.describe("MassEntityConfig asset to edit."),
23702
+ 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}`),
23703
+ projectId: creativeProjectIdSchema
23704
+ };
23705
+ const getMassEntityConfigInputSchema = {
23706
+ assetPath: bridgeGetMassEntityConfigRequestSchema.shape.assetPath.describe("MassEntityConfig asset to read."),
23707
+ projectId: creativeProjectIdSchema
23708
+ };
23709
+ const validateMassEntityConfigInputSchema = {
23710
+ assetPath: bridgeValidateMassEntityConfigRequestSchema.shape.assetPath.describe("MassEntityConfig asset to validate."),
23711
+ projectId: creativeProjectIdSchema
23712
+ };
23713
+ async function createMassEntityConfig(input, dependencies) {
23714
+ return await exchangeCreativeRequest(createBridgeCreateMassEntityConfigRequest(input.assetName, input.packagePath, { parentConfigPath: input.parentConfigPath }), sendBridgeCreateMassEntityConfigRequest, BRIDGE_CREATE_MASS_ENTITY_CONFIG_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
23715
+ }
23716
+ async function editMassEntityConfig(input, dependencies) {
23717
+ return await exchangeCreativeRequest(createBridgeEditMassEntityConfigRequest(input.assetPath, input.edits), sendBridgeEditMassEntityConfigRequest, BRIDGE_EDIT_MASS_ENTITY_CONFIG_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
23718
+ }
23719
+ async function getMassEntityConfig(input, dependencies) {
23720
+ return await exchangeCreativeRequest(createBridgeGetMassEntityConfigRequest(input.assetPath), sendBridgeGetMassEntityConfigRequest, BRIDGE_GET_MASS_ENTITY_CONFIG_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
23721
+ }
23722
+ async function validateMassEntityConfig(input, dependencies) {
23723
+ return await exchangeCreativeRequest(createBridgeValidateMassEntityConfigRequest(input.assetPath), sendBridgeValidateMassEntityConfigRequest, BRIDGE_VALIDATE_MASS_ENTITY_CONFIG_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
23724
+ }
23725
+ function registerMassTools(server, dependencies) {
23726
+ server.registerTool("create_mass_entity_config", {
23727
+ 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.",
23728
+ inputSchema: createMassEntityConfigInputSchema,
23729
+ title: "Create Mass Entity Config"
23730
+ }, async ({ assetName, packagePath, parentConfigPath, projectId }) => {
23731
+ return toToolSuccess(await createMassEntityConfig({
23732
+ assetName,
23733
+ packagePath,
23734
+ parentConfigPath,
23735
+ projectId
23736
+ }, dependencies));
23737
+ });
23738
+ server.registerTool("edit_mass_entity_config", {
23739
+ 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.",
23740
+ inputSchema: editMassEntityConfigInputSchema,
23741
+ title: "Edit Mass Entity Config"
23742
+ }, async ({ assetPath, edits, projectId }) => {
23743
+ return toToolSuccess(await editMassEntityConfig({
23744
+ assetPath,
23745
+ edits,
23746
+ projectId
23747
+ }, dependencies));
23748
+ });
23749
+ server.registerTool("get_mass_entity_config", {
23750
+ 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.",
23751
+ inputSchema: getMassEntityConfigInputSchema,
23752
+ title: "Get Mass Entity Config"
23753
+ }, async ({ assetPath, projectId }) => {
23754
+ return toToolSuccess(await getMassEntityConfig({
23755
+ assetPath,
23756
+ projectId
23757
+ }, dependencies));
23758
+ });
23759
+ server.registerTool("validate_mass_entity_config", {
23760
+ 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).",
23761
+ inputSchema: validateMassEntityConfigInputSchema,
23762
+ title: "Validate Mass Entity Config"
23763
+ }, async ({ assetPath, projectId }) => {
23764
+ return toToolSuccess(await validateMassEntityConfig({
23765
+ assetPath,
23766
+ projectId
23767
+ }, dependencies));
23768
+ });
23769
+ }
23770
+ const massToolDomain = {
23771
+ domain: "mass",
23772
+ register: registerMassTools,
23773
+ toolNames: [
23774
+ "create_mass_entity_config",
23775
+ "edit_mass_entity_config",
23776
+ "get_mass_entity_config",
23777
+ "validate_mass_entity_config"
23778
+ ]
23779
+ };
23780
+ //#endregion
22835
23781
  //#region src/tools/material.ts
22836
23782
  const createMaterialInstanceInputSchema = {
22837
23783
  assetName: bridgeCreateMaterialInstanceRequestSchema.shape.assetName.describe("Name of the new instance, e.g. 'MI_Rock_Mossy'."),
@@ -23102,6 +24048,13 @@ const testReachabilityInputSchema = {
23102
24048
  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
24049
  projectId: creativeProjectIdSchema
23104
24050
  };
24051
+ const diagnoseNavmeshInputSchema = {
24052
+ includePlayerStarts: bridgeDiagnoseNavmeshRequestSchema.shape.includePlayerStarts.describe("Check every PlayerStart in the level as a spawn point. Defaults to true."),
24053
+ maxIslands: bridgeDiagnoseNavmeshRequestSchema.shape.maxIslands.describe(`Most islands to list, largest area first (1-${String(64)}). islandCount stays the full count.`),
24054
+ navMeshActorPath: bridgeDiagnoseNavmeshRequestSchema.shape.navMeshActorPath.describe("Actor path of the RecastNavMesh to inspect. Omit to use the level's main navigation data."),
24055
+ projectId: creativeProjectIdSchema,
24056
+ spawnActorPaths: bridgeDiagnoseNavmeshRequestSchema.shape.spawnActorPaths.describe(`Extra spawn actors to check alongside the player starts, such as AI spawners (max ${String(64)}).`)
24057
+ };
23105
24058
  async function setNavmeshSettings(input, dependencies) {
23106
24059
  return await exchangeCreativeRequest(createBridgeSetNavmeshSettingsRequest({
23107
24060
  agentHeight: input.agentHeight,
@@ -23172,6 +24125,14 @@ async function testReachability(input, dependencies) {
23172
24125
  navMeshActorPath: input.navMeshActorPath
23173
24126
  }), sendBridgeTestReachabilityRequest, BRIDGE_TEST_REACHABILITY_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
23174
24127
  }
24128
+ async function diagnoseNavmesh(input, dependencies) {
24129
+ return await exchangeCreativeRequest(createBridgeDiagnoseNavmeshRequest({
24130
+ includePlayerStarts: input.includePlayerStarts,
24131
+ maxIslands: input.maxIslands,
24132
+ navMeshActorPath: input.navMeshActorPath,
24133
+ spawnActorPaths: input.spawnActorPaths
24134
+ }), sendBridgeDiagnoseNavmeshRequest, BRIDGE_DIAGNOSE_NAVMESH_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
24135
+ }
23175
24136
  function registerNavigationTools(server, dependencies) {
23176
24137
  server.registerTool("set_navmesh_settings", {
23177
24138
  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 +24250,19 @@ function registerNavigationTools(server, dependencies) {
23289
24250
  projectId
23290
24251
  }, dependencies));
23291
24252
  });
24253
+ server.registerTool("diagnose_navmesh", {
24254
+ 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.",
24255
+ inputSchema: diagnoseNavmeshInputSchema,
24256
+ title: "Diagnose Navmesh"
24257
+ }, async ({ includePlayerStarts, maxIslands, navMeshActorPath, projectId, spawnActorPaths }) => {
24258
+ return toToolSuccess(await diagnoseNavmesh({
24259
+ includePlayerStarts,
24260
+ maxIslands,
24261
+ navMeshActorPath,
24262
+ projectId,
24263
+ spawnActorPaths
24264
+ }, dependencies));
24265
+ });
23292
24266
  }
23293
24267
  const navigationToolDomain = {
23294
24268
  domain: "navigation",
@@ -23301,7 +24275,8 @@ const navigationToolDomain = {
23301
24275
  "add_nav_modifier_volume",
23302
24276
  "add_nav_link",
23303
24277
  "find_path",
23304
- "test_reachability"
24278
+ "test_reachability",
24279
+ "diagnose_navmesh"
23305
24280
  ]
23306
24281
  };
23307
24282
  //#endregion
@@ -24218,6 +25193,90 @@ const sequencerToolDomain = {
24218
25193
  ]
24219
25194
  };
24220
25195
  //#endregion
25196
+ //#region src/tools/smartObjects.ts
25197
+ const createSmartObjectDefinitionInputSchema = {
25198
+ activityTags: bridgeCreateSmartObjectDefinitionRequestSchema.shape.activityTags.describe("Gameplay tags describing what the whole object offers, e.g. 'Activity.Sit'. Every tag must already be registered."),
25199
+ assetName: bridgeCreateSmartObjectDefinitionRequestSchema.shape.assetName.describe("Name of the new Smart Object definition, e.g. 'SOD_Bench'."),
25200
+ 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."),
25201
+ packagePath: bridgeCreateSmartObjectDefinitionRequestSchema.shape.packagePath.describe("Content folder to create the definition in."),
25202
+ projectId: creativeProjectIdSchema,
25203
+ 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.")
25204
+ };
25205
+ const getSmartObjectDefinitionInputSchema = {
25206
+ assetPath: bridgeGetSmartObjectDefinitionRequestSchema.shape.assetPath.describe("Object path of the Smart Object definition to read."),
25207
+ projectId: creativeProjectIdSchema
25208
+ };
25209
+ const addSmartObjectComponentInputSchema = {
25210
+ actorPath: bridgeAddSmartObjectComponentRequestFieldsSchema.shape.actorPath.describe("Placed actor in the editor level to add the component to. Give this or blueprintPath, not both."),
25211
+ blueprintPath: bridgeAddSmartObjectComponentRequestFieldsSchema.shape.blueprintPath.describe("Actor Blueprint to add the component to; the Blueprint is recompiled. Give this or actorPath, not both."),
25212
+ componentName: bridgeAddSmartObjectComponentRequestFieldsSchema.shape.componentName.describe("Name of the component. Omitted reuses the existing Smart Object component, or names a new one SmartObject."),
25213
+ definitionPath: bridgeAddSmartObjectComponentRequestFieldsSchema.shape.definitionPath.describe("Smart Object definition the component points at."),
25214
+ projectId: creativeProjectIdSchema
25215
+ };
25216
+ async function createSmartObjectDefinition(input, dependencies) {
25217
+ return await exchangeCreativeRequest(createBridgeCreateSmartObjectDefinitionRequest(input.assetName, input.packagePath, input.slots, {
25218
+ activityTags: input.activityTags,
25219
+ defaultBehaviorDefinitions: input.defaultBehaviorDefinitions
25220
+ }), sendBridgeCreateSmartObjectDefinitionRequest, BRIDGE_CREATE_SMART_OBJECT_DEFINITION_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
25221
+ }
25222
+ async function getSmartObjectDefinition(input, dependencies) {
25223
+ return await exchangeCreativeRequest(createBridgeGetSmartObjectDefinitionRequest(input.assetPath), sendBridgeGetSmartObjectDefinitionRequest, BRIDGE_GET_SMART_OBJECT_DEFINITION_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
25224
+ }
25225
+ async function addSmartObjectComponent(input, dependencies) {
25226
+ return await exchangeCreativeRequest(createBridgeAddSmartObjectComponentRequest(input.definitionPath, {
25227
+ actorPath: input.actorPath,
25228
+ blueprintPath: input.blueprintPath
25229
+ }, { componentName: input.componentName }), sendBridgeAddSmartObjectComponentRequest, BRIDGE_ADD_SMART_OBJECT_COMPONENT_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
25230
+ }
25231
+ function registerSmartObjectsTools(server, dependencies) {
25232
+ server.registerTool("create_smart_object_definition", {
25233
+ 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.",
25234
+ inputSchema: createSmartObjectDefinitionInputSchema,
25235
+ title: "Create Smart Object Definition"
25236
+ }, async ({ activityTags, assetName, defaultBehaviorDefinitions, packagePath, projectId, slots }) => {
25237
+ return toToolSuccess(await createSmartObjectDefinition({
25238
+ activityTags,
25239
+ assetName,
25240
+ defaultBehaviorDefinitions,
25241
+ packagePath,
25242
+ projectId,
25243
+ slots
25244
+ }, dependencies));
25245
+ });
25246
+ server.registerTool("get_smart_object_definition", {
25247
+ 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.",
25248
+ inputSchema: getSmartObjectDefinitionInputSchema,
25249
+ title: "Get Smart Object Definition"
25250
+ }, async ({ assetPath, projectId }) => {
25251
+ return toToolSuccess(await getSmartObjectDefinition({
25252
+ assetPath,
25253
+ projectId
25254
+ }, dependencies));
25255
+ });
25256
+ server.registerTool("add_smart_object_component", {
25257
+ 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.",
25258
+ inputSchema: addSmartObjectComponentInputSchema,
25259
+ title: "Add Smart Object Component"
25260
+ }, async ({ actorPath, blueprintPath, componentName, definitionPath, projectId }) => {
25261
+ return toToolSuccess(await addSmartObjectComponent({
25262
+ actorPath,
25263
+ blueprintPath,
25264
+ componentName,
25265
+ definitionPath,
25266
+ projectId
25267
+ }, dependencies));
25268
+ });
25269
+ }
25270
+ const smartObjectsToolDomain = {
25271
+ domain: "smartObjects",
25272
+ register: registerSmartObjectsTools,
25273
+ toolNames: [
25274
+ "create_smart_object_definition",
25275
+ "get_smart_object_definition",
25276
+ "add_smart_object_component"
25277
+ ]
25278
+ };
25279
+ //#endregion
24221
25280
  //#region src/tools/stateTree.ts
24222
25281
  const getStateTreeInputSchema = {
24223
25282
  assetPath: bridgeGetStateTreeRequestSchema.shape.assetPath.describe("Object path of the StateTree asset to read."),
@@ -24256,6 +25315,18 @@ const traceStateTreeInputSchema = {
24256
25315
  maxEvents: bridgeTraceStateTreeRequestSchema.shape.maxEvents.describe("Maximum events to return in one poll (1-200, default 50)."),
24257
25316
  projectId: creativeProjectIdSchema
24258
25317
  };
25318
+ const updateStateTreeElementsInputSchema = {
25319
+ assetPath: bridgeUpdateStateTreeElementsRequestSchema.shape.assetPath.describe("Object path of the StateTree asset to edit."),
25320
+ compile: bridgeUpdateStateTreeElementsRequestSchema.shape.compile.describe("Run the StateTree compiler after the edits. Defaults true; its messages come back verbatim in compileMessages."),
25321
+ projectId: creativeProjectIdSchema,
25322
+ 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'.")
25323
+ };
25324
+ const removeStateTreeElementsInputSchema = {
25325
+ assetPath: bridgeRemoveStateTreeElementsRequestSchema.shape.assetPath.describe("Object path of the StateTree asset to edit."),
25326
+ compile: bridgeRemoveStateTreeElementsRequestSchema.shape.compile.describe("Run the StateTree compiler after the removals. Defaults true; its messages come back verbatim in compileMessages."),
25327
+ projectId: creativeProjectIdSchema,
25328
+ 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.")
25329
+ };
24259
25330
  async function getStateTree(input, dependencies) {
24260
25331
  return await exchangeCreativeRequest(createBridgeGetStateTreeRequest(input.assetPath), sendBridgeGetStateTreeRequest, BRIDGE_GET_STATE_TREE_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
24261
25332
  }
@@ -24284,6 +25355,12 @@ async function traceStateTree(input, dependencies) {
24284
25355
  maxEvents: input.maxEvents
24285
25356
  }), sendBridgeTraceStateTreeRequest, BRIDGE_TRACE_STATE_TREE_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
24286
25357
  }
25358
+ async function updateStateTreeElements(input, dependencies) {
25359
+ return await exchangeCreativeRequest(createBridgeUpdateStateTreeElementsRequest(input.assetPath, input.updates, { compile: input.compile }), sendBridgeUpdateStateTreeElementsRequest, BRIDGE_UPDATE_STATE_TREE_ELEMENTS_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
25360
+ }
25361
+ async function removeStateTreeElements(input, dependencies) {
25362
+ return await exchangeCreativeRequest(createBridgeRemoveStateTreeElementsRequest(input.assetPath, input.removals, { compile: input.compile }), sendBridgeRemoveStateTreeElementsRequest, BRIDGE_REMOVE_STATE_TREE_ELEMENTS_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
25363
+ }
24287
25364
  function registerStateTreeTools(server, dependencies) {
24288
25365
  server.registerTool("get_state_tree", {
24289
25366
  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 +25435,30 @@ function registerStateTreeTools(server, dependencies) {
24358
25435
  projectId
24359
25436
  }, dependencies));
24360
25437
  });
25438
+ server.registerTool("update_state_tree_elements", {
25439
+ 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.",
25440
+ inputSchema: updateStateTreeElementsInputSchema,
25441
+ title: "Update StateTree Elements"
25442
+ }, async ({ assetPath, compile, projectId, updates }) => {
25443
+ return toToolSuccess(await updateStateTreeElements({
25444
+ assetPath,
25445
+ compile,
25446
+ projectId,
25447
+ updates
25448
+ }, dependencies));
25449
+ });
25450
+ server.registerTool("remove_state_tree_elements", {
25451
+ 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.",
25452
+ inputSchema: removeStateTreeElementsInputSchema,
25453
+ title: "Remove StateTree Elements"
25454
+ }, async ({ assetPath, compile, projectId, removals }) => {
25455
+ return toToolSuccess(await removeStateTreeElements({
25456
+ assetPath,
25457
+ compile,
25458
+ projectId,
25459
+ removals
25460
+ }, dependencies));
25461
+ });
24361
25462
  }
24362
25463
  const stateTreeToolDomain = {
24363
25464
  domain: "stateTree",
@@ -24368,7 +25469,9 @@ const stateTreeToolDomain = {
24368
25469
  "set_state_tree_considerations",
24369
25470
  "link_state_tree_state",
24370
25471
  "add_state_tree_component",
24371
- "trace_state_tree"
25472
+ "trace_state_tree",
25473
+ "update_state_tree_elements",
25474
+ "remove_state_tree_elements"
24372
25475
  ]
24373
25476
  };
24374
25477
  //#endregion
@@ -25294,7 +26397,9 @@ const TOOL_CATALOG = [
25294
26397
  vfxToolDomain,
25295
26398
  pcgToolDomain,
25296
26399
  projectSettingsToolDomain,
25297
- navigationToolDomain
26400
+ navigationToolDomain,
26401
+ smartObjectsToolDomain,
26402
+ massToolDomain
25298
26403
  ];
25299
26404
  //#endregion
25300
26405
  //#region src/mcpTools.ts