Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
9bc1074
feat(grpc): trace and events for ExecuteAction
devin-ai-integration[bot] Oct 30, 2026
573f6c0
feat(client): trace and events options for ExecuteAction in the Go an…
devin-ai-integration[bot] Oct 30, 2026
5d66d4f
feat(client): trace and events options for ExecuteAction in the Node …
devin-ai-integration[bot] Oct 30, 2026
a072220
feat(client): trace and events options for ExecuteAction in the Rust …
devin-ai-integration[bot] Oct 30, 2026
031ab54
feat(client): trace and events options for ExecuteAction in the Julia…
devin-ai-integration[bot] Oct 30, 2026
ef2763d
test: traced ExecuteAction over the wasm engine and the mission-seque…
devin-ai-integration[bot] Oct 30, 2026
c2367cd
test(runtime): robustness of traced action runs and undelivered events
devin-ai-integration[bot] Oct 30, 2026
d5dc483
fix(client): action_trace served by the MCP execute_action tool; Octa…
devin-ai-integration[bot] Oct 30, 2026
6d1ca22
Merge remote-tracking branch 'origin/feat/engine-state-advance' into …
devin-ai-integration[bot] Oct 30, 2026
9570767
Merge remote-tracking branch 'origin/develop' into feat/execute-actio…
devin-ai-integration[bot] Oct 30, 2026
eca4e93
Merge remote-tracking branch 'origin/develop' into feat/execute-actio…
devin-ai-integration[bot] Oct 30, 2026
53b4b7b
fix(runtime,clients): release failed event runs, record held assign v…
devin-ai-integration[bot] Oct 30, 2026
f4b0069
fix(runtime): keep a qualified target's written value in its assign r…
devin-ai-integration[bot] Oct 30, 2026
b331451
fix(runtime): read a qualified assign target back through its owner
devin-ai-integration[bot] Oct 30, 2026
917ae2e
Merge remote-tracking branch 'origin/develop' into feat/execute-actio…
devin-ai-integration[bot] Oct 30, 2026
f1bab66
test(syson): build DocumentEvent with its action trace components
devin-ai-integration[bot] Oct 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
675 changes: 393 additions & 282 deletions api/proto/sysml.pb.go

Large diffs are not rendered by default.

53 changes: 48 additions & 5 deletions api/proto/sysml.proto
Original file line number Diff line number Diff line change
Expand Up @@ -1118,6 +1118,23 @@ message ExecuteActionRequest {
// default, is a continuous clock; a negative or non-finite step is
// INVALID_ARGUMENT.
double clock_step = 9;
// Ask for the run's trace in ExecuteActionResponse.trace. Advertised as the
// "action_trace" capability; a service withholding it refuses true with
// UNIMPLEMENTED, as does an explore schedule with INVALID_ARGUMENT.
bool trace = 10;
// Signals or items to post to the performing object, in this order, as the
// REPL's `%send` does: the run goes until it completes or every token waits,
// the next event is then posted to the object's queue and the run goes on,
// an accept node waiting for it taking it on the next step. An event of a
// type no accept node of the performance names is refused, with the accepts
// still waiting. The events exhausted, the run goes on to completion (or for
// `advance`); a token still waiting at the end is an accept deadlock,
// reported in `error` with the message it waits for. Each names a signal or
// item definition, qualified or as the action's namespace sees it; a name no
// definition answers to is matched by name alone, as ExecuteState's events
// are. Posted to the object performer_symbol_id names, as `%send` posts to
// one: INVALID_ARGUMENT without it.
repeated string events = 11;
}

// ExecuteActionResponse contains action execution results
Expand All @@ -1144,6 +1161,13 @@ message ExecuteActionResponse {
// output nothing order-dependent wrote is absent. Populated under the
// "order_dependence" capability; empty under an explore schedule.
map<string, int32> order_dependent = 8;
// The run's trace in the order the run made it, when the request asked for
// it: the token steps, waits, accepts, sends, decisions, assignments and
// completion of the action, each a DocumentEvent (see its `kind`), also on a
// run that failed, up to the failure. Empty under an explore schedule.
repeated DocumentEvent trace = 9;
// How many of the oldest records the service's held-events bound discarded.
int32 trace_dropped = 10;
}

// ExecuteStateRequest requests state machine execution
Expand Down Expand Up @@ -2852,7 +2876,12 @@ message DocumentState {
// DocumentEvent is one row an `Events` query answered: one record of the
// session's trace, in the order the run made it.
message DocumentEvent {
// "accept", "send", "transition", "entry", "exit", "do", "choice", "guard" or "terminate".
// "accept", "send", "transition", "entry", "exit", "do", "choice", "guard" or
// "terminate" for a state machine's records; an action's run adds "step" (a
// token arriving at a node), "wait" (a token parking at an accept node),
// "assign" (a feature written), "decide" (a decision node resolved) and
// "complete" (the action's performance completed); its "accept" is the accept
// node taking a message and its "send" a message posted.
string kind = 1;
// The clock's instant when the record was made: a quantity in the clock's
// unit when the library reduces one, else a bare real of clock units.
Expand All @@ -2863,23 +2892,37 @@ message DocumentEvent {
// The behavior the record is about, by the name the object exhibits it
// under, else its declared name; empty for the run's own records.
string machine = 4;
// The state entered, exited or stepped by an entry, exit or do record.
// The state entered, exited or stepped by an entry, exit or do record; the
// action node a wait, assign, decide or action accept record is at.
string state = 5;
// A fired transition's source and target states.
// A fired transition's source and target states; a step's source node (empty
// where the token's flow starts) and the node it arrived at; a decide's
// branch taken, as `taken` names it.
string from = 6;
string to = 7;
// The object a send was addressed to; unset for every other kind and a
// send addressed to no object.
DocumentObject target = 8;
// The signal or event accepted or sent, or the trigger a transition fired on.
// The signal or event accepted or sent, the trigger a transition fired on, or
// the message type or trigger a wait record waits for.
string event = 9;
// An accept's payload, one `name = value` entry per parameter in name order.
repeated string payload = 10;
// A choice's alternatives, in the order they were offered, and the one taken.
// A choice's alternatives, in the order they were offered, and the one taken;
// a decide's branches as `<position>-><target node>`, and the one taken.
repeated string alternatives = 11;
string taken = 12;
// The line the trace prints for the record.
string text = 13;
// The action token a step, wait, assign, decide or action accept record is
// about, and the executor step (1-based) that made the record; 0 for a record
// of neither (a state machine's, a send from outside the model).
int64 token = 14;
int32 step = 15;
// The feature an assign record wrote and the value it holds since, as the
// run's outputs carry values.
string feature = 16;
Value value = 17;
}

// DocumentQueryColumn is one projected property, in projection order.
Expand Down
1 change: 1 addition & 0 deletions changes/unreleased/execute-action-trace-events.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- `ExecuteAction` takes `trace` and `events`: the run's trace comes back as `DocumentEvent` records of each token step, wait, accept, send, decision, assignment and the completion (capability `action_trace`, in the wasm module too), and the events are posted to the performer in turn as the run waits, as the REPL's `%send` does; every client passes both options.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ public record ActionRun(
Map<String, Value> outputs,
OptionalDouble finalTime,
List<Diagnostic> diagnostics,
Map<String, Value> performer) {
Map<String, Value> performer,
List<DocumentValue.DocumentEvent> trace,
int traceDropped) {

/**
* Creates an action run, copying its collections.
Expand All @@ -28,12 +30,31 @@ public record ActionRun(
* @param finalTime the final time, when reported
* @param diagnostics the diagnostics
* @param performer the performer's attributes by outcome key
* @param trace the run's records when a trace was asked for, in order
* @param traceDropped oldest trace records the service discarded
*/
public ActionRun {
outputs = Map.copyOf(outputs);
Objects.requireNonNull(finalTime, "finalTime");
diagnostics = List.copyOf(diagnostics);
performer = Map.copyOf(performer);
trace = List.copyOf(trace);
}

/**
* Creates an untraced action run.
*
* @param outputs the outputs by name
* @param finalTime the final time, when reported
* @param diagnostics the diagnostics
* @param performer the performer's attributes by outcome key
*/
public ActionRun(
Map<String, Value> outputs,
OptionalDouble finalTime,
List<Diagnostic> diagnostics,
Map<String, Value> performer) {
this(outputs, finalTime, diagnostics, performer, List.of(), 0);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,9 @@ public final class Capabilities {
/** The {@code trace} field on {@code ExecuteStateRequest}. */
public static final String STATE_TRACE = "state_trace";

/** The {@code trace} field on {@code ExecuteActionRequest}: the run's token steps, waits, accepts, decisions and assignments. */
public static final String ACTION_TRACE = "action_trace";

/** The execution responses report {@code final_time}, the run's simulation clock when it ended, in seconds. */
public static final String FINAL_TIME = "final_time";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,9 @@ record DocumentState(
* binding one is refused.
*
* @param kind {@code "accept"}, {@code "send"}, {@code "transition"}, {@code "entry"}, {@code
* "exit"}, {@code "do"}, {@code "choice"}, {@code "guard"} or {@code "terminate"}
* "exit"}, {@code "do"}, {@code "choice"}, {@code "guard"} or {@code "terminate"}; an action's
* run adds {@code "step"}, {@code "wait"}, {@code "assign"}, {@code "decide"} and {@code
* "complete"}
* @param time the instant the record was written at, in the runtime clock's unit — a {@link
* QuantityValue} when the clock carries a unit, a plain number otherwise
* @param text the record as the trace prints it
Expand All @@ -278,7 +280,12 @@ record DocumentState(
* @param event the accepted or sent event's type name
* @param payload the accept's payload, one {@code name = value} text per attribute
* @param alternatives what a choice drew from, in order
* @param taken the alternative the choice took
* @param taken the alternative the choice took, or the branch a decide took
* @param token the action token a step, wait, assign, decide or accept record is about; 0 for a
* record of none
* @param step the executor step that made the record; 0 for none
* @param feature the feature an assign record wrote
* @param value what that feature holds since; absent for every other kind
*/
record DocumentEvent(
String kind,
Expand All @@ -293,7 +300,11 @@ record DocumentEvent(
String event,
List<String> payload,
List<String> alternatives,
String taken)
String taken,
long token,
int step,
String feature,
Optional<Value> value)
implements DocumentValue {

/**
Expand All @@ -312,6 +323,10 @@ record DocumentEvent(
* @param payload the payload entries
* @param alternatives the alternatives
* @param taken the one taken, never {@code null}
* @param token the token, 0 for none
* @param step the executor step, 0 for none
* @param feature the assigned feature, never {@code null}
* @param value the assigned value, when there is one
*/
public DocumentEvent {
Objects.requireNonNull(kind, "kind");
Expand All @@ -327,6 +342,8 @@ record DocumentEvent(
payload = List.copyOf(payload);
alternatives = List.copyOf(alternatives);
Objects.requireNonNull(taken, "taken");
Objects.requireNonNull(feature, "feature");
Objects.requireNonNull(value, "value");
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.openmbee.opensysml;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalDouble;
Expand All @@ -15,7 +16,7 @@
* @param performer the object the behavior runs on, as {@code sysml -action "<action> <object>"}
* names it: a part definition or usage to make an object of, or a path from one into its parts
* ({@code "Mission::mission.vehicle"}), made for the run. Absent runs outside any object.
* @param trace whether a state run returns its documented execution trace
* @param trace whether a state or action run returns its documented execution trace
* @param advance simulated time, in seconds, to run for ({@code sysml -advance}): the behavior is
* started and its clock moved by this much; an action not completed by then fails with the
* instant it waits for. Absent runs to completion.
Expand All @@ -25,6 +26,9 @@
* default), {@code "min"}, {@code "max"} or {@code "average"}
* @param clockStep the step, in seconds, the run's clock ticks by ({@code sysml -clock-step}); 0
* is a continuous clock
* @param events signals to post to an action's performer in order, each once every token of the
* run waits, as the REPL's {@code %send} does; the accept waiting for one takes it on the next
* step. Needs a performer. (A state run's events are an argument of its own.)
*/
public record ExecutionOptions(
Optional<String> schedule,
Expand All @@ -33,7 +37,8 @@ public record ExecutionOptions(
OptionalDouble advance,
OptionalLong seed,
Optional<String> draws,
double clockStep) {
double clockStep,
List<String> events) {

private static final String EXPLORE = "explore";

Expand All @@ -49,6 +54,7 @@ public record ExecutionOptions(
Objects.requireNonNull(advance, "advance");
Objects.requireNonNull(seed, "seed");
Objects.requireNonNull(draws, "draws");
events = List.copyOf(events);
}

/**
Expand All @@ -64,7 +70,8 @@ public static ExecutionOptions defaults() {
OptionalDouble.empty(),
OptionalLong.empty(),
Optional.empty(),
0);
0,
List.of());
}

/**
Expand All @@ -75,7 +82,7 @@ public static ExecutionOptions defaults() {
*/
public ExecutionOptions withSchedule(String schedule) {
return new ExecutionOptions(
Optional.of(schedule), performer, trace, advance, seed, draws, clockStep);
Optional.of(schedule), performer, trace, advance, seed, draws, clockStep, events);
}

/**
Expand All @@ -86,12 +93,13 @@ public ExecutionOptions withSchedule(String schedule) {
*/
public ExecutionOptions withPerformer(String performer) {
return new ExecutionOptions(
schedule, Optional.of(performer), trace, advance, seed, draws, clockStep);
schedule, Optional.of(performer), trace, advance, seed, draws, clockStep, events);
}

/** The same options with a state-run trace requested. */
public ExecutionOptions withTrace() {
return new ExecutionOptions(schedule, performer, true, advance, seed, draws, clockStep);
return new ExecutionOptions(
schedule, performer, true, advance, seed, draws, clockStep, events);
}

/**
Expand All @@ -102,7 +110,7 @@ public ExecutionOptions withTrace() {
*/
public ExecutionOptions withAdvance(double seconds) {
return new ExecutionOptions(
schedule, performer, trace, OptionalDouble.of(seconds), seed, draws, clockStep);
schedule, performer, trace, OptionalDouble.of(seconds), seed, draws, clockStep, events);
}

/**
Expand All @@ -113,7 +121,7 @@ public ExecutionOptions withAdvance(double seconds) {
*/
public ExecutionOptions withSeed(long seed) {
return new ExecutionOptions(
schedule, performer, trace, advance, OptionalLong.of(seed), draws, clockStep);
schedule, performer, trace, advance, OptionalLong.of(seed), draws, clockStep, events);
}

/**
Expand All @@ -124,7 +132,7 @@ public ExecutionOptions withSeed(long seed) {
*/
public ExecutionOptions withDraws(String draws) {
return new ExecutionOptions(
schedule, performer, trace, advance, seed, Optional.of(draws), clockStep);
schedule, performer, trace, advance, seed, Optional.of(draws), clockStep, events);
}

/**
Expand All @@ -134,7 +142,19 @@ public ExecutionOptions withDraws(String draws) {
* @return options ticking by it
*/
public ExecutionOptions withClockStep(double seconds) {
return new ExecutionOptions(schedule, performer, trace, advance, seed, draws, seconds);
return new ExecutionOptions(
schedule, performer, trace, advance, seed, draws, seconds, events);
}

/**
* Posts these signals to the action's performer, in order, as the run waits.
*
* @param events the signal or item definitions to post, qualified or as the action sees them
* @return these options with the events
*/
public ExecutionOptions withEvents(String... events) {
return new ExecutionOptions(
schedule, performer, trace, advance, seed, draws, clockStep, List.of(events));
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.
Resolved
}

/**
Expand Down
Loading
Loading