Let a nested behavior without a start node run from On start (#230)
A behavior built as a plain behavior, with On start and no Behavior start, did nothing when another behavior called it through Run behavior. The node only showed a warning. Such a behavior should run as a call too, without the author having to rebuild its entry. - New callEntries() in nested.ts returns the Behavior start node or, when there is none, every On start node. callProblem uses it too. - GraphInterpreter.call() follows all entries one after the other, in graph order, in the same frame and with the same variables. - Behavior end still returns what reaches it. A call through On start has no inputs, because only the start node declares them. - It is a fallback only. With a Behavior start present, On start nodes stay out of the call. - The node warning now reads "No start or On start node - does nothing" and only shows when neither exists. - Keep and local state machines behave as before. Tests: - ./check.sh: 163 files, 2396 tests, CHECK EXIT 0 (before 2392). - 4 new unit tests in tests/core/nested-behavior.test.ts: the flow after On start runs, the return value arrives, several On start nodes run in graph order, a start node keeps On start out. - e2e 19: ALL PASSED, 35 checks. Only the expected warning text changed, the check sum stays at 1385. - Counter-checks: without the fallback 3 tests fail. With only the first On start exactly the order test fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
454d202109
commit
21d7149756
5 files changed
+117
-33
No files matched your search
@@ -20,6 +20,7 @@ export const BEHAVIOR_END = 'BehaviorEnd';
|
||||
export const RUN_BEHAVIOR = 'RunBehavior';
|
||||
export const VARIABLES = 'Variables';
|
||||
export const PROPERTIES = 'Properties';
|
||||
export const ON_START = 'OnStart';
|
||||
|
||||
export const BEHAVIOR_PARAM = 'behavior';
|
||||
export const VARIABLES_PARAM = 'variablesAsset';
|
||||
@@ -92,6 +93,15 @@ export function terminalNode(graph: Graph, type: string): GraphNode | undefined
|
||||
return graph.nodes.find((n) => n.type === type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Where a call into `graph` begins: its start node, or – for a behavior that has none – every
|
||||
* `On start` in it, in graph order, as when the behavior starts on its own (#230).
|
||||
*/
|
||||
export function callEntries(graph: Graph): GraphNode[] {
|
||||
const start = terminalNode(graph, BEHAVIOR_START);
|
||||
return start ? [start] : graph.nodes.filter((n) => n.type === ON_START);
|
||||
}
|
||||
|
||||
export function isTerminalType(type: string): boolean {
|
||||
return type === BEHAVIOR_START || type === BEHAVIOR_END;
|
||||
}
|
||||
@@ -267,7 +277,7 @@ export function callProblem(node: GraphNode, lookup: GraphLookup, ownerId = ''):
|
||||
if (id === ownerId) return 'A behavior cannot run itself';
|
||||
const program = lookup.behavior(id);
|
||||
if (!program) return 'That behavior is gone';
|
||||
if (!terminalNode(program.graph, BEHAVIOR_START)) return 'No start node – does nothing';
|
||||
if (callEntries(program.graph).length === 0) return 'No start or On start node – does nothing';
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user