@angflow/angular 0.0.17 → 0.0.19

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 (170) hide show
  1. package/README.md +53 -0
  2. package/dist/base.css +18 -0
  3. package/dist/esm/lib/agent/agent-bridge.service.d.ts +6 -2
  4. package/dist/esm/lib/agent/agent-bridge.service.d.ts.map +1 -1
  5. package/dist/esm/lib/agent/agent-bridge.service.js +228 -5
  6. package/dist/esm/lib/agent/agent-bridge.service.js.map +1 -1
  7. package/dist/esm/lib/agent/chat/agent-chat.component.d.ts +20 -0
  8. package/dist/esm/lib/agent/chat/agent-chat.component.d.ts.map +1 -0
  9. package/dist/esm/lib/agent/chat/agent-chat.component.js +174 -0
  10. package/dist/esm/lib/agent/chat/agent-chat.component.js.map +1 -0
  11. package/dist/esm/lib/agent/chat/agent-chat.service.d.ts +43 -0
  12. package/dist/esm/lib/agent/chat/agent-chat.service.d.ts.map +1 -0
  13. package/dist/esm/lib/agent/chat/agent-chat.service.js +226 -0
  14. package/dist/esm/lib/agent/chat/agent-chat.service.js.map +1 -0
  15. package/dist/esm/lib/agent/chat/default-system-prompt.d.ts +6 -0
  16. package/dist/esm/lib/agent/chat/default-system-prompt.d.ts.map +1 -0
  17. package/dist/esm/lib/agent/chat/default-system-prompt.js +14 -0
  18. package/dist/esm/lib/agent/chat/default-system-prompt.js.map +1 -0
  19. package/dist/esm/lib/agent/chat/index.d.ts +7 -0
  20. package/dist/esm/lib/agent/chat/index.d.ts.map +1 -0
  21. package/dist/esm/lib/agent/chat/index.js +5 -0
  22. package/dist/esm/lib/agent/chat/index.js.map +1 -0
  23. package/dist/esm/lib/agent/chat/provide-agent-chat.d.ts +29 -0
  24. package/dist/esm/lib/agent/chat/provide-agent-chat.d.ts.map +1 -0
  25. package/dist/esm/lib/agent/chat/provide-agent-chat.js +40 -0
  26. package/dist/esm/lib/agent/chat/provide-agent-chat.js.map +1 -0
  27. package/dist/esm/lib/agent/chat/types.d.ts +77 -0
  28. package/dist/esm/lib/agent/chat/types.d.ts.map +1 -0
  29. package/dist/esm/lib/agent/chat/types.js +9 -0
  30. package/dist/esm/lib/agent/chat/types.js.map +1 -0
  31. package/dist/esm/lib/agent/index.d.ts +1 -0
  32. package/dist/esm/lib/agent/index.d.ts.map +1 -1
  33. package/dist/esm/lib/agent/index.js +1 -0
  34. package/dist/esm/lib/agent/index.js.map +1 -1
  35. package/dist/esm/lib/agent/provide-agent-bridge.d.ts +8 -0
  36. package/dist/esm/lib/agent/provide-agent-bridge.d.ts.map +1 -1
  37. package/dist/esm/lib/agent/provide-agent-bridge.js +2 -1
  38. package/dist/esm/lib/agent/provide-agent-bridge.js.map +1 -1
  39. package/dist/esm/lib/agent/tool-schemas.d.ts.map +1 -1
  40. package/dist/esm/lib/agent/tool-schemas.js +138 -0
  41. package/dist/esm/lib/agent/tool-schemas.js.map +1 -1
  42. package/dist/esm/lib/components/a11y-descriptions/a11y-descriptions.component.js +3 -3
  43. package/dist/esm/lib/components/a11y-descriptions/a11y-descriptions.component.js.map +1 -1
  44. package/dist/esm/lib/components/attribution/attribution.component.js +3 -3
  45. package/dist/esm/lib/components/attribution/attribution.component.js.map +1 -1
  46. package/dist/esm/lib/components/background/background.component.js +3 -3
  47. package/dist/esm/lib/components/background/background.component.js.map +1 -1
  48. package/dist/esm/lib/components/connection-line/connection-line.component.js +3 -3
  49. package/dist/esm/lib/components/connection-line/connection-line.component.js.map +1 -1
  50. package/dist/esm/lib/components/controls/controls.component.js +3 -3
  51. package/dist/esm/lib/components/controls/controls.component.js.map +1 -1
  52. package/dist/esm/lib/components/edge-label-renderer/edge-label-renderer.component.js +3 -3
  53. package/dist/esm/lib/components/edge-label-renderer/edge-label-renderer.component.js.map +1 -1
  54. package/dist/esm/lib/components/edge-toolbar/edge-toolbar.component.d.ts +2 -2
  55. package/dist/esm/lib/components/edge-toolbar/edge-toolbar.component.js +3 -3
  56. package/dist/esm/lib/components/edge-toolbar/edge-toolbar.component.js.map +1 -1
  57. package/dist/esm/lib/components/edges/base-edge.component.js +3 -3
  58. package/dist/esm/lib/components/edges/base-edge.component.js.map +1 -1
  59. package/dist/esm/lib/components/edges/bezier-edge.component.js +3 -3
  60. package/dist/esm/lib/components/edges/bezier-edge.component.js.map +1 -1
  61. package/dist/esm/lib/components/edges/edge-text.component.js +3 -3
  62. package/dist/esm/lib/components/edges/edge-text.component.js.map +1 -1
  63. package/dist/esm/lib/components/edges/simple-bezier-edge.component.js +3 -3
  64. package/dist/esm/lib/components/edges/simple-bezier-edge.component.js.map +1 -1
  65. package/dist/esm/lib/components/edges/smooth-step-edge.component.js +3 -3
  66. package/dist/esm/lib/components/edges/smooth-step-edge.component.js.map +1 -1
  67. package/dist/esm/lib/components/edges/step-edge.component.js +3 -3
  68. package/dist/esm/lib/components/edges/step-edge.component.js.map +1 -1
  69. package/dist/esm/lib/components/edges/straight-edge.component.js +3 -3
  70. package/dist/esm/lib/components/edges/straight-edge.component.js.map +1 -1
  71. package/dist/esm/lib/components/handle/handle.component.js +3 -3
  72. package/dist/esm/lib/components/handle/handle.component.js.map +1 -1
  73. package/dist/esm/lib/components/handle-group/handle-group.component.d.ts +1 -1
  74. package/dist/esm/lib/components/handle-group/handle-group.component.js +3 -3
  75. package/dist/esm/lib/components/handle-group/handle-group.component.js.map +1 -1
  76. package/dist/esm/lib/components/handle-group/handle-row.component.js +3 -3
  77. package/dist/esm/lib/components/handle-group/handle-row.component.js.map +1 -1
  78. package/dist/esm/lib/components/minimap/minimap.component.d.ts +17 -8
  79. package/dist/esm/lib/components/minimap/minimap.component.d.ts.map +1 -1
  80. package/dist/esm/lib/components/minimap/minimap.component.js +63 -39
  81. package/dist/esm/lib/components/minimap/minimap.component.js.map +1 -1
  82. package/dist/esm/lib/components/ng-flow-provider/ng-flow-provider.component.js +3 -3
  83. package/dist/esm/lib/components/ng-flow-provider/ng-flow-provider.component.js.map +1 -1
  84. package/dist/esm/lib/components/node-resizer/node-resizer.component.js +3 -3
  85. package/dist/esm/lib/components/node-resizer/node-resizer.component.js.map +1 -1
  86. package/dist/esm/lib/components/node-toolbar/node-toolbar.component.js +3 -3
  87. package/dist/esm/lib/components/node-toolbar/node-toolbar.component.js.map +1 -1
  88. package/dist/esm/lib/components/nodes/default-node.component.js +3 -3
  89. package/dist/esm/lib/components/nodes/default-node.component.js.map +1 -1
  90. package/dist/esm/lib/components/nodes/group-node.component.js +3 -3
  91. package/dist/esm/lib/components/nodes/group-node.component.js.map +1 -1
  92. package/dist/esm/lib/components/nodes/input-node.component.js +3 -3
  93. package/dist/esm/lib/components/nodes/input-node.component.js.map +1 -1
  94. package/dist/esm/lib/components/nodes/output-node.component.js +3 -3
  95. package/dist/esm/lib/components/nodes/output-node.component.js.map +1 -1
  96. package/dist/esm/lib/components/nodes/template-node.component.d.ts +48 -0
  97. package/dist/esm/lib/components/nodes/template-node.component.d.ts.map +1 -0
  98. package/dist/esm/lib/components/nodes/template-node.component.js +209 -0
  99. package/dist/esm/lib/components/nodes/template-node.component.js.map +1 -0
  100. package/dist/esm/lib/components/panel/panel.component.js +3 -3
  101. package/dist/esm/lib/components/panel/panel.component.js.map +1 -1
  102. package/dist/esm/lib/components/selection-box/selection-box.component.js +3 -3
  103. package/dist/esm/lib/components/selection-box/selection-box.component.js.map +1 -1
  104. package/dist/esm/lib/components/viewport-portal/viewport-portal.component.js +3 -3
  105. package/dist/esm/lib/components/viewport-portal/viewport-portal.component.js.map +1 -1
  106. package/dist/esm/lib/container/edge-renderer/edge-renderer.component.d.ts.map +1 -1
  107. package/dist/esm/lib/container/edge-renderer/edge-renderer.component.js +9 -5
  108. package/dist/esm/lib/container/edge-renderer/edge-renderer.component.js.map +1 -1
  109. package/dist/esm/lib/container/ng-flow/ng-flow.component.d.ts +19 -1
  110. package/dist/esm/lib/container/ng-flow/ng-flow.component.d.ts.map +1 -1
  111. package/dist/esm/lib/container/ng-flow/ng-flow.component.js +28 -4
  112. package/dist/esm/lib/container/ng-flow/ng-flow.component.js.map +1 -1
  113. package/dist/esm/lib/container/node-renderer/node-renderer.component.d.ts +5 -0
  114. package/dist/esm/lib/container/node-renderer/node-renderer.component.d.ts.map +1 -1
  115. package/dist/esm/lib/container/node-renderer/node-renderer.component.js +71 -7
  116. package/dist/esm/lib/container/node-renderer/node-renderer.component.js.map +1 -1
  117. package/dist/esm/lib/container/pane/pane.component.js +3 -3
  118. package/dist/esm/lib/container/pane/pane.component.js.map +1 -1
  119. package/dist/esm/lib/container/viewport/viewport.component.js +3 -3
  120. package/dist/esm/lib/container/viewport/viewport.component.js.map +1 -1
  121. package/dist/esm/lib/directives/drag.directive.js +3 -3
  122. package/dist/esm/lib/directives/drag.directive.js.map +1 -1
  123. package/dist/esm/lib/directives/drop-zone.directive.js +3 -3
  124. package/dist/esm/lib/directives/drop-zone.directive.js.map +1 -1
  125. package/dist/esm/lib/directives/key-handler.directive.js +3 -3
  126. package/dist/esm/lib/directives/key-handler.directive.js.map +1 -1
  127. package/dist/esm/lib/directives/node-type.directive.js +3 -3
  128. package/dist/esm/lib/directives/node-type.directive.js.map +1 -1
  129. package/dist/esm/lib/layout/dagre-layout.d.ts +12 -0
  130. package/dist/esm/lib/layout/dagre-layout.d.ts.map +1 -0
  131. package/dist/esm/lib/layout/dagre-layout.js +13 -0
  132. package/dist/esm/lib/layout/dagre-layout.js.map +1 -0
  133. package/dist/esm/lib/layout/index.d.ts +4 -0
  134. package/dist/esm/lib/layout/index.d.ts.map +1 -0
  135. package/dist/esm/lib/layout/index.js +3 -0
  136. package/dist/esm/lib/layout/index.js.map +1 -0
  137. package/dist/esm/lib/layout/layout-nodes.d.ts +47 -0
  138. package/dist/esm/lib/layout/layout-nodes.d.ts.map +1 -0
  139. package/dist/esm/lib/layout/layout-nodes.js +49 -0
  140. package/dist/esm/lib/layout/layout-nodes.js.map +1 -0
  141. package/dist/esm/lib/public-api.d.ts +2 -1
  142. package/dist/esm/lib/public-api.d.ts.map +1 -1
  143. package/dist/esm/lib/public-api.js +4 -1
  144. package/dist/esm/lib/public-api.js.map +1 -1
  145. package/dist/esm/lib/services/flow-store.service.d.ts +52 -2
  146. package/dist/esm/lib/services/flow-store.service.d.ts.map +1 -1
  147. package/dist/esm/lib/services/flow-store.service.js +145 -3
  148. package/dist/esm/lib/services/flow-store.service.js.map +1 -1
  149. package/dist/esm/lib/services/ng-flow.service.d.ts +81 -0
  150. package/dist/esm/lib/services/ng-flow.service.d.ts.map +1 -1
  151. package/dist/esm/lib/services/ng-flow.service.js +127 -3
  152. package/dist/esm/lib/services/ng-flow.service.js.map +1 -1
  153. package/dist/esm/lib/types/index.d.ts +1 -0
  154. package/dist/esm/lib/types/index.d.ts.map +1 -1
  155. package/dist/esm/lib/types/index.js +1 -0
  156. package/dist/esm/lib/types/index.js.map +1 -1
  157. package/dist/esm/lib/types/node-template.d.ts +77 -0
  158. package/dist/esm/lib/types/node-template.d.ts.map +1 -0
  159. package/dist/esm/lib/types/node-template.js +10 -0
  160. package/dist/esm/lib/types/node-template.js.map +1 -0
  161. package/dist/esm/lib/utils/position-tween.d.ts +19 -0
  162. package/dist/esm/lib/utils/position-tween.d.ts.map +1 -0
  163. package/dist/esm/lib/utils/position-tween.js +25 -0
  164. package/dist/esm/lib/utils/position-tween.js.map +1 -0
  165. package/dist/esm/lib/utils/template-interpolation.d.ts +16 -0
  166. package/dist/esm/lib/utils/template-interpolation.d.ts.map +1 -0
  167. package/dist/esm/lib/utils/template-interpolation.js +51 -0
  168. package/dist/esm/lib/utils/template-interpolation.js.map +1 -0
  169. package/dist/style.css +18 -0
  170. package/package.json +78 -66
package/README.md CHANGED
@@ -180,6 +180,59 @@ flowService.screenToFlowPosition({ x: event.clientX, y: event.clientY });
180
180
  flowService.toObject(); // { nodes, edges, viewport }
181
181
  ```
182
182
 
183
+ ## Floating Edges
184
+
185
+ Set `edgeMode="floating"` and edges attach wherever the line to the peer node's
186
+ center crosses each node's border — no handle declarations needed:
187
+
188
+ ```html
189
+ <ng-flow [nodes]="nodes" [edges]="edges" edgeMode="floating" />
190
+ ```
191
+
192
+ Works with nodes that declare zero handles, which makes it ideal for
193
+ programmatic / agent-driven graphs. Note: a node with no handles cannot
194
+ originate an interactive drag-connection — declared handles still work for
195
+ starting connections while rendering stays floating. For per-edge control in
196
+ the default mode, set `floating` on individual handles instead:
197
+ `<ng-flow-handle type="source" [floating]="true" />`.
198
+
199
+ ## Auto-Layout
200
+
201
+ `layoutNodes` is a pure dagre wrapper — feed it your nodes and edges, get back
202
+ a map of top-left positions:
203
+
204
+ ```ts
205
+ import { layoutNodes } from '@angflow/angular/layout'; // needs @dagrejs/dagre installed
206
+
207
+ const positions = layoutNodes(flow.getNodes(), flow.getEdges(), { direction: 'LR' });
208
+ flow.setNodePositions(positions);
209
+
210
+ // or in one call:
211
+ flow.applyLayout(layoutNodes, { direction: 'LR' });
212
+ ```
213
+
214
+ Options: `direction` (`'TB' | 'LR' | 'BT' | 'RL'`, default `'TB'`), `nodeSep`
215
+ (default 50), `rankSep` (default 80). Node dimensions resolve from
216
+ `measured` → `width`/`height` → `initialWidth`/`initialHeight` → 150×40. Any
217
+ function with the same shape plugs
218
+ into `applyLayout` (elk, custom grids, …).
219
+
220
+ ## Animations
221
+
222
+ Turn on `[animate]` and the flow animates node entries (fade + scale) and
223
+ programmatic position changes (smooth tween, edges tracking mid-flight):
224
+
225
+ ```html
226
+ <ng-flow [nodes]="nodes" [edges]="edges" [animate]="true" />
227
+ <!-- or tune the duration: -->
228
+ <ng-flow [animate]="{ duration: 200 }" />
229
+ ```
230
+
231
+ Animated paths: `setNodePositions`, `applyLayout`, and the agent bridge's
232
+ `layout_nodes` tool. Dragging is never animated, a drag cancels any in-flight
233
+ tween on that node, and everything is disabled under `prefers-reduced-motion`.
234
+ Per-call override: `flow.setNodePositions(positions, { animate: false })`.
235
+
183
236
  ## Architecture
184
237
 
185
238
  - **Signal-based state** — Angular 17+ signals for fine-grained reactivity (no RxJS in the store)
package/dist/base.css CHANGED
@@ -955,6 +955,24 @@ svg.xy-flow__connectionline {
955
955
  }
956
956
 
957
957
 
958
+ /* Entry animation — applied by the node renderer when [animate] is enabled.
959
+ Uses the standalone `scale` property so it composes with the inline
960
+ translate() transform instead of overriding it. */
961
+ .xy-flow__node-enter {
962
+ animation: xy-flow-node-enter 300ms ease both;
963
+ transform-origin: 50% 50%;
964
+ }
965
+
966
+ @keyframes xy-flow-node-enter {
967
+ from { opacity: 0; scale: 0.92; }
968
+ to { opacity: 1; scale: 1; }
969
+ }
970
+
971
+ @media (prefers-reduced-motion: reduce) {
972
+ .xy-flow__node-enter { animation: none; }
973
+ }
974
+
975
+
958
976
  .xy-flow__node-input,
959
977
  .xy-flow__node-default,
960
978
  .xy-flow__node-output,
@@ -1,5 +1,6 @@
1
1
  import { InjectionToken } from '@angular/core';
2
2
  import type { NgFlowService } from '../services/ng-flow.service';
3
+ import type { AgentLayoutFn } from '../types/node-template';
3
4
  import type { AgentHistoryOptions } from './history';
4
5
  import type { AgentTransport } from './types';
5
6
  import * as i0 from "@angular/core";
@@ -13,6 +14,8 @@ export declare const AGENT_ON_ERROR: InjectionToken<(err: unknown, ctx: {
13
14
  transport?: AgentTransport;
14
15
  method?: string;
15
16
  }) => void>;
17
+ /** Optional host-provided layout function backing the `layout_nodes` tool. */
18
+ export declare const AGENT_LAYOUT: InjectionToken<AgentLayoutFn>;
16
19
  /**
17
20
  * Routes JSON-RPC requests from one or more transports to registered
18
21
  * `NgFlowService` instances, and pushes change events back to the agent.
@@ -45,6 +48,7 @@ export declare class AngflowAgentBridge {
45
48
  private readonly history;
46
49
  private readonly handlers;
47
50
  private readonly injector;
51
+ private readonly layoutFn;
48
52
  private started;
49
53
  private nextInProcessId;
50
54
  private warnedOnBeforeDeleteBypass;
@@ -55,7 +59,7 @@ export declare class AngflowAgentBridge {
55
59
  kind: 'transport-start' | 'transport-send' | 'dispatch';
56
60
  transport?: AgentTransport;
57
61
  method?: string;
58
- }) => void) | null);
62
+ }) => void) | null, layoutFn: AgentLayoutFn | null);
59
63
  private reportError;
60
64
  /**
61
65
  * Register a flow under `id`. The bridge subscribes to its `nodes`,
@@ -85,7 +89,7 @@ export declare class AngflowAgentBridge {
85
89
  private resolveFlow;
86
90
  private watchFlow;
87
91
  private installHandlers;
88
- static ɵfac: i0.ɵɵFactoryDeclaration<AngflowAgentBridge, [{ optional: true; }, { optional: true; }, { optional: true; }]>;
92
+ static ɵfac: i0.ɵɵFactoryDeclaration<AngflowAgentBridge, [{ optional: true; }, { optional: true; }, { optional: true; }, { optional: true; }]>;
89
93
  static ɵprov: i0.ɵɵInjectableDeclaration<AngflowAgentBridge>;
90
94
  }
91
95
  //# sourceMappingURL=agent-bridge.service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent-bridge.service.d.ts","sourceRoot":"","sources":["../../../../src/lib/agent/agent-bridge.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,cAAc,EAOf,MAAM,eAAe,CAAC;AAEvB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAGjE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAErD,OAAO,KAAK,EAGV,cAAc,EAEf,MAAM,SAAS,CAAC;;AAEjB,6DAA6D;AAC7D,eAAO,MAAM,gBAAgB,kCAAiE,CAAC;AAE/F,4EAA4E;AAC5E,eAAO,MAAM,qBAAqB,6CAEjC,CAAC;AAEF,0FAA0F;AAC1F,eAAO,MAAM,cAAc,uBACnB,OAAO,OAAO;IAAE,IAAI,EAAE,iBAAiB,GAAG,gBAAgB,GAAG,UAAU,CAAC;IAAC,SAAS,CAAC,EAAE,cAAc,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,IAAI,CAC/G,CAAC;AAiCzB;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBACa,kBAAkB;IAC7B,uFAAuF;IACvF,QAAQ,CAAC,WAAW,sCAAsB;IAE1C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAC3D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAmB;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkC;IAC3D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoB;IAC7C,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,0BAA0B,CAAS;IAE3C,8EAA8E;IAC9E,QAAQ,CAAC,eAAe,mDAAwB;IAEhD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAEf;gBAG+B,UAAU,EAAE,cAAc,EAAE,GAAG,IAAI,EAC9B,cAAc,EAAE,mBAAmB,GAAG,KAAK,GAAG,IAAI,EACzD,OAAO,EAAE,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE;QAAE,IAAI,EAAE,iBAAiB,GAAG,gBAAgB,GAAG,UAAU,CAAC;QAAC,SAAS,CAAC,EAAE,cAAc,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC,GAAG,IAAI;IAU7L,OAAO,CAAC,WAAW;IASnB;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,MAAM,IAAI;IAuBrD,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAU5B,iCAAiC;IACjC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAI9C;;;;;OAKG;IACG,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAiBtF,OAAO,CAAC,KAAK;YAiBC,QAAQ;IAqFtB,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,IAAI;IAYZ,OAAO,CAAC,WAAW;IAiBnB,OAAO,CAAC,SAAS;IAgDjB,OAAO,CAAC,eAAe;yCAhTZ,kBAAkB;6CAAlB,kBAAkB;CAqrB9B"}
1
+ {"version":3,"file":"agent-bridge.service.d.ts","sourceRoot":"","sources":["../../../../src/lib/agent/agent-bridge.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,cAAc,EAOf,MAAM,eAAe,CAAC;AAEvB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAEjE,OAAO,KAAK,EAAE,aAAa,EAAoB,MAAM,wBAAwB,CAAC;AAE9E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAErD,OAAO,KAAK,EAGV,cAAc,EAEf,MAAM,SAAS,CAAC;;AAEjB,6DAA6D;AAC7D,eAAO,MAAM,gBAAgB,kCAAiE,CAAC;AAE/F,4EAA4E;AAC5E,eAAO,MAAM,qBAAqB,6CAEjC,CAAC;AAEF,0FAA0F;AAC1F,eAAO,MAAM,cAAc,uBACnB,OAAO,OAAO;IAAE,IAAI,EAAE,iBAAiB,GAAG,gBAAgB,GAAG,UAAU,CAAC;IAAC,SAAS,CAAC,EAAE,cAAc,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,IAAI,CAC/G,CAAC;AAEzB,8EAA8E;AAC9E,eAAO,MAAM,YAAY,+BAA0D,CAAC;AAiCpF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBACa,kBAAkB;IAC7B,uFAAuF;IACvF,QAAQ,CAAC,WAAW,sCAAsB;IAE1C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAC3D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAmB;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkC;IAC3D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoB;IAC7C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuB;IAChD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,0BAA0B,CAAS;IAE3C,8EAA8E;IAC9E,QAAQ,CAAC,eAAe,mDAAwB;IAEhD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAEf;gBAG+B,UAAU,EAAE,cAAc,EAAE,GAAG,IAAI,EAC9B,cAAc,EAAE,mBAAmB,GAAG,KAAK,GAAG,IAAI,EACzD,OAAO,EAAE,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE;QAAE,IAAI,EAAE,iBAAiB,GAAG,gBAAgB,GAAG,UAAU,CAAC;QAAC,SAAS,CAAC,EAAE,cAAc,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC,GAAG,IAAI,EACzJ,QAAQ,EAAE,aAAa,GAAG,IAAI;IAWlE,OAAO,CAAC,WAAW;IASnB;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,MAAM,IAAI;IAuBrD,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAU5B,iCAAiC;IACjC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAI9C;;;;;OAKG;IACG,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAiBtF,OAAO,CAAC,KAAK;YAiBC,QAAQ;IAkGtB,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,IAAI;IAYZ,OAAO,CAAC,WAAW;IAiBnB,OAAO,CAAC,SAAS;IAgDjB,OAAO,CAAC,eAAe;yCAhUZ,kBAAkB;6CAAlB,kBAAkB;CA20B9B"}
@@ -8,6 +8,8 @@ export const AGENT_TRANSPORTS = new InjectionToken('AngflowAgentTransports');
8
8
  export const AGENT_HISTORY_OPTIONS = new InjectionToken('AngflowAgentHistoryOptions');
9
9
  /** Optional error sink. Receives transport/dispatch failures that the bridge swallows. */
10
10
  export const AGENT_ON_ERROR = new InjectionToken('AngflowAgentOnError');
11
+ /** Optional host-provided layout function backing the `layout_nodes` tool. */
12
+ export const AGENT_LAYOUT = new InjectionToken('AngflowAgentLayout');
11
13
  const ERROR_INVALID_PARAMS = -32602;
12
14
  const ERROR_METHOD_NOT_FOUND = -32601;
13
15
  const ERROR_FLOW_NOT_FOUND = -32000;
@@ -50,7 +52,7 @@ const MUTATING_TOOLS = new Set([
50
52
  * ```
51
53
  */
52
54
  export class AngflowAgentBridge {
53
- constructor(transports, historyOptions, onError) {
55
+ constructor(transports, historyOptions, onError, layoutFn) {
54
56
  /** Schemas for every exposed tool — feed straight to a Claude / OpenAI tools array. */
55
57
  this.toolSchemas = AGENT_TOOL_SCHEMAS;
56
58
  this.flows = new Map();
@@ -65,6 +67,7 @@ export class AngflowAgentBridge {
65
67
  this.history =
66
68
  historyOptions === false ? null : new AgentHistory(historyOptions ?? undefined);
67
69
  this.onError = onError ?? null;
70
+ this.layoutFn = layoutFn ?? null;
68
71
  this.installHandlers();
69
72
  this.start();
70
73
  }
@@ -175,12 +178,13 @@ export class AngflowAgentBridge {
175
178
  const flow = this.resolveFlow(params['flowId']);
176
179
  const flowId = this.findFlowId(flow);
177
180
  const isApplyChanges = req.method === 'apply_changes';
181
+ const isLayout = req.method === 'layout_nodes';
178
182
  // Pre-mutation snapshot for history capture. Skipped for non-mutating tools.
179
183
  // Shallow-clone each element so subsequent in-place mutations (notably
180
184
  // the drag fast-path in FlowStore) can't retroactively corrupt the
181
185
  // snapshot we already captured.
182
186
  let snapshot = null;
183
- if (this.history && (MUTATING_TOOLS.has(req.method) || isApplyChanges)) {
187
+ if (this.history && (MUTATING_TOOLS.has(req.method) || isApplyChanges || isLayout)) {
184
188
  snapshot = {
185
189
  nodes: flow.getNodes().map((n) => ({ ...n })),
186
190
  edges: flow.getEdges().map((e) => ({ ...e })),
@@ -200,6 +204,15 @@ export class AngflowAgentBridge {
200
204
  this.emitHistory(flowId);
201
205
  }
202
206
  }
207
+ else if (isLayout) {
208
+ // Capture only when at least one position was applied — an empty
209
+ // layout pass must not pollute the undo stack.
210
+ const positions = result?.positions ?? {};
211
+ if (Object.keys(positions).length > 0) {
212
+ this.history.capture(flowId, snapshot);
213
+ this.emitHistory(flowId);
214
+ }
215
+ }
203
216
  else {
204
217
  this.history.capture(flowId, snapshot);
205
218
  this.emitHistory(flowId);
@@ -211,6 +224,9 @@ export class AngflowAgentBridge {
211
224
  if (err instanceof FlowNotFoundError) {
212
225
  return { id: req.id, error: { code: ERROR_FLOW_NOT_FOUND, message: err.message } };
213
226
  }
227
+ if (err instanceof MethodUnavailableError) {
228
+ return { id: req.id, error: { code: ERROR_METHOD_NOT_FOUND, message: err.message } };
229
+ }
214
230
  if (err instanceof InvalidParamsError) {
215
231
  return { id: req.id, error: { code: ERROR_INVALID_PARAMS, message: err.message } };
216
232
  }
@@ -669,11 +685,129 @@ export class AngflowAgentBridge {
669
685
  this.history.clear(flowId);
670
686
  this.emitHistory(flowId);
671
687
  });
688
+ this.handlers.set('list_node_types', (flow) => ({ types: flow.getNodeTypeNames() }));
689
+ this.handlers.set('list_edge_types', (flow) => ({ types: flow.getEdgeTypeNames() }));
690
+ this.handlers.set('register_node_template', (flow, params) => {
691
+ const name = requireString(params, 'name');
692
+ if (name.length === 0) {
693
+ throw new InvalidParamsError('Param "name" must be a non-empty string.');
694
+ }
695
+ const spec = validateTemplateSpec(requireObject(params, 'spec'), 'register_node_template');
696
+ const claimed = flow
697
+ .getNodeTypeNames()
698
+ .find((t) => t.name === name && t.source !== 'template');
699
+ if (claimed) {
700
+ throw new InvalidParamsError(`register_node_template: "${name}" is already registered by the ` +
701
+ `${claimed.source === 'builtin' ? 'library' : 'host application'} and cannot be overridden.`);
702
+ }
703
+ flow.registerNodeTemplate(name, spec);
704
+ return { name };
705
+ });
706
+ this.handlers.set('unregister_node_template', (flow, params) => {
707
+ const name = requireString(params, 'name');
708
+ return { removed: flow.unregisterNodeTemplate(name) };
709
+ });
710
+ this.handlers.set('list_node_templates', (flow) => ({
711
+ templates: flow.getNodeTemplates(),
712
+ }));
713
+ this.handlers.set('layout_nodes', async (flow, params) => {
714
+ if (!this.layoutFn) {
715
+ throw new MethodUnavailableError('layout_nodes unavailable: no layout function configured. ' +
716
+ 'Pass `layout` to provideAgentBridge (e.g. dagreLayout from @angflow/angular/layout).');
717
+ }
718
+ const direction = params['direction'] ?? 'TB';
719
+ if (typeof direction !== 'string' || !['TB', 'LR', 'BT', 'RL'].includes(direction)) {
720
+ throw new InvalidParamsError('Param "direction" must be one of: TB, LR, BT, RL.');
721
+ }
722
+ const nodeSep = typeof params['nodeSep'] === 'number' ? params['nodeSep'] : undefined;
723
+ const rankSep = typeof params['rankSep'] === 'number' ? params['rankSep'] : undefined;
724
+ const nodeIds = optionalStringArray(params, 'nodeIds');
725
+ if (nodeIds) {
726
+ for (const id of nodeIds) {
727
+ if (!flow.getNode(id)) {
728
+ throw new InvalidParamsError(`Param "nodeIds" contains unknown node id "${id}".`);
729
+ }
730
+ }
731
+ }
732
+ const targetNodes = nodeIds
733
+ ? nodeIds.map((id) => flow.getNode(id))
734
+ : flow.getNodes();
735
+ const idSet = new Set(targetNodes.map((n) => n.id));
736
+ const layoutNodes = targetNodes.map((n) => {
737
+ const internal = flow.getInternalNode(n.id);
738
+ return {
739
+ id: n.id,
740
+ width: internal?.measured?.width ?? n.width ?? 150,
741
+ height: internal?.measured?.height ?? n.height ?? 40,
742
+ position: { x: n.position.x, y: n.position.y },
743
+ };
744
+ });
745
+ // Induced subgraph: only edges with BOTH endpoints in the target set.
746
+ const layoutEdges = flow
747
+ .getEdges()
748
+ .filter((e) => idSet.has(e.source) && idSet.has(e.target))
749
+ .map((e) => ({ source: e.source, target: e.target }));
750
+ const raw = await this.layoutFn(layoutNodes, layoutEdges, {
751
+ direction: direction,
752
+ nodeSep,
753
+ rankSep,
754
+ });
755
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
756
+ throw new Error('layout function must return an object map of nodeId -> {x, y}.');
757
+ }
758
+ // Validate the full result BEFORE applying anything so a bad position
759
+ // rolls back cleanly (nothing applied, no history entry).
760
+ const applied = {};
761
+ const unknownIds = [];
762
+ for (const [id, pos] of Object.entries(raw)) {
763
+ if (!idSet.has(id)) {
764
+ unknownIds.push(id);
765
+ continue;
766
+ }
767
+ if (!pos ||
768
+ typeof pos.x !== 'number' ||
769
+ typeof pos.y !== 'number' ||
770
+ !Number.isFinite(pos.x) ||
771
+ !Number.isFinite(pos.y)) {
772
+ throw new Error(`layout function returned an invalid position for node "${id}"`);
773
+ }
774
+ applied[id] = { x: pos.x, y: pos.y };
775
+ }
776
+ if (unknownIds.length > 0) {
777
+ // eslint-disable-next-line no-console
778
+ console.warn(`[angflow] layout_nodes: layout function returned positions for unknown node ids ` +
779
+ `(ignored): ${unknownIds.join(', ')}`);
780
+ }
781
+ // Re-check existence at apply time: the graph may have changed while the
782
+ // (possibly async) layout fn ran — e.g. a human deleted a node. Only
783
+ // nodes that still exist are moved, reported, and counted for history.
784
+ const actuallyApplied = {};
785
+ for (const [id, position] of Object.entries(applied)) {
786
+ if (!flow.getNode(id))
787
+ continue;
788
+ actuallyApplied[id] = position;
789
+ }
790
+ // Honors the host's [animate] input: positions tween when it's on, and
791
+ // the await keeps the subsequent fitView measuring settled positions.
792
+ await flow.setNodePositions(actuallyApplied);
793
+ const shouldFit = params['fitView'] !== false;
794
+ if (shouldFit && Object.keys(actuallyApplied).length > 0) {
795
+ try {
796
+ await flow.fitView({});
797
+ }
798
+ catch (err) {
799
+ // Best-effort viewport fit: never fail the tool over a cosmetic step,
800
+ // but surface the error to hosts observing onError.
801
+ this.reportError(err, { kind: 'dispatch', method: 'layout_nodes' });
802
+ }
803
+ }
804
+ return { positions: actuallyApplied };
805
+ });
672
806
  }
673
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: AngflowAgentBridge, deps: [{ token: AGENT_TRANSPORTS, optional: true }, { token: AGENT_HISTORY_OPTIONS, optional: true }, { token: AGENT_ON_ERROR, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
674
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: AngflowAgentBridge, providedIn: 'root' }); }
807
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: AngflowAgentBridge, deps: [{ token: AGENT_TRANSPORTS, optional: true }, { token: AGENT_HISTORY_OPTIONS, optional: true }, { token: AGENT_ON_ERROR, optional: true }, { token: AGENT_LAYOUT, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
808
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: AngflowAgentBridge, providedIn: 'root' }); }
675
809
  }
676
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: AngflowAgentBridge, decorators: [{
810
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: AngflowAgentBridge, decorators: [{
677
811
  type: Injectable,
678
812
  args: [{ providedIn: 'root' }]
679
813
  }], ctorParameters: () => [{ type: undefined, decorators: [{
@@ -691,11 +825,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
691
825
  }, {
692
826
  type: Inject,
693
827
  args: [AGENT_ON_ERROR]
828
+ }] }, { type: undefined, decorators: [{
829
+ type: Optional
830
+ }, {
831
+ type: Inject,
832
+ args: [AGENT_LAYOUT]
694
833
  }] }] });
695
834
  class FlowNotFoundError extends Error {
696
835
  }
697
836
  class InvalidParamsError extends Error {
698
837
  }
838
+ /** Tool exists in the catalog but the deployment lacks a required capability. Maps to -32601. */
839
+ class MethodUnavailableError extends Error {
840
+ }
699
841
  class ApplyChangesError extends Error {
700
842
  constructor(failedIndex, message) {
701
843
  super(message);
@@ -893,6 +1035,87 @@ function optionalStringArray(params, key) {
893
1035
  }
894
1036
  return value;
895
1037
  }
1038
+ const BADGE_COLOR_SET = new Set(['slate', 'indigo', 'emerald', 'amber', 'rose']);
1039
+ const HANDLE_POSITION_SET = new Set(['top', 'right', 'bottom', 'left']);
1040
+ const KNOWN_SPEC_KEYS = new Set(['title', 'icon', 'accent', 'variant', 'badges', 'fields', 'body', 'handles']);
1041
+ /** Validate a NodeTemplateSpec payload. Throws InvalidParamsError naming the offending field. */
1042
+ function validateTemplateSpec(value, ctx) {
1043
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
1044
+ throw new InvalidParamsError(`${ctx}: spec must be an object.`);
1045
+ }
1046
+ const s = value;
1047
+ for (const key of Object.keys(s)) {
1048
+ if (!KNOWN_SPEC_KEYS.has(key)) {
1049
+ throw new InvalidParamsError(`${ctx}: unknown spec key "${key}".`);
1050
+ }
1051
+ }
1052
+ for (const key of ['title', 'icon', 'accent', 'body']) {
1053
+ if (s[key] !== undefined && typeof s[key] !== 'string') {
1054
+ throw new InvalidParamsError(`${ctx}: spec.${key} must be a string.`);
1055
+ }
1056
+ }
1057
+ if (s['variant'] !== undefined && s['variant'] !== 'compact' && s['variant'] !== 'detailed') {
1058
+ throw new InvalidParamsError(`${ctx}: spec.variant must be "compact" or "detailed".`);
1059
+ }
1060
+ if (s['badges'] !== undefined) {
1061
+ if (!Array.isArray(s['badges']))
1062
+ throw new InvalidParamsError(`${ctx}: spec.badges must be an array.`);
1063
+ s['badges'].forEach((raw, i) => {
1064
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
1065
+ throw new InvalidParamsError(`${ctx}: spec.badges[${i}] must be an object.`);
1066
+ }
1067
+ const b = raw;
1068
+ if (typeof b['text'] !== 'string') {
1069
+ throw new InvalidParamsError(`${ctx}: spec.badges[${i}].text must be a string.`);
1070
+ }
1071
+ if (b['color'] !== undefined && !BADGE_COLOR_SET.has(b['color'])) {
1072
+ throw new InvalidParamsError(`${ctx}: spec.badges[${i}].color must be one of: ${Array.from(BADGE_COLOR_SET).join(', ')}.`);
1073
+ }
1074
+ if (b['showIf'] !== undefined && typeof b['showIf'] !== 'string') {
1075
+ throw new InvalidParamsError(`${ctx}: spec.badges[${i}].showIf must be a string.`);
1076
+ }
1077
+ });
1078
+ }
1079
+ if (s['fields'] !== undefined) {
1080
+ if (!Array.isArray(s['fields']))
1081
+ throw new InvalidParamsError(`${ctx}: spec.fields must be an array.`);
1082
+ s['fields'].forEach((raw, i) => {
1083
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
1084
+ throw new InvalidParamsError(`${ctx}: spec.fields[${i}] must be an object.`);
1085
+ }
1086
+ const f = raw;
1087
+ if (typeof f['label'] !== 'string') {
1088
+ throw new InvalidParamsError(`${ctx}: spec.fields[${i}].label must be a string.`);
1089
+ }
1090
+ if (typeof f['value'] !== 'string') {
1091
+ throw new InvalidParamsError(`${ctx}: spec.fields[${i}].value must be a string.`);
1092
+ }
1093
+ if (f['showIf'] !== undefined && typeof f['showIf'] !== 'string') {
1094
+ throw new InvalidParamsError(`${ctx}: spec.fields[${i}].showIf must be a string.`);
1095
+ }
1096
+ });
1097
+ }
1098
+ if (s['handles'] !== undefined) {
1099
+ if (!Array.isArray(s['handles']))
1100
+ throw new InvalidParamsError(`${ctx}: spec.handles must be an array.`);
1101
+ s['handles'].forEach((raw, i) => {
1102
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
1103
+ throw new InvalidParamsError(`${ctx}: spec.handles[${i}] must be an object.`);
1104
+ }
1105
+ const h = raw;
1106
+ if (h['type'] !== 'source' && h['type'] !== 'target') {
1107
+ throw new InvalidParamsError(`${ctx}: spec.handles[${i}].type must be "source" or "target".`);
1108
+ }
1109
+ if (h['position'] !== undefined && !HANDLE_POSITION_SET.has(h['position'])) {
1110
+ throw new InvalidParamsError(`${ctx}: spec.handles[${i}].position must be one of: top, right, bottom, left.`);
1111
+ }
1112
+ if (h['id'] !== undefined && typeof h['id'] !== 'string') {
1113
+ throw new InvalidParamsError(`${ctx}: spec.handles[${i}].id must be a string.`);
1114
+ }
1115
+ });
1116
+ }
1117
+ return value;
1118
+ }
896
1119
  /** Validate that `value` is a structurally valid Node payload for add_*. */
897
1120
  function validateNodeShape(value, ctx) {
898
1121
  if (!value || typeof value !== 'object' || Array.isArray(value)) {