              :choices :any
              :tags [:fault-tolerance]
              :restrictions ["Must resolve to a function on the classpath at runtime."]
-             :optional? true}
+             :optional? true
+             :added "0.8.0"}
 
             :onyx/params
             {:doc "A vector of keys to obtain from the task map, and inject into the parameters of the function defined in :onyx/fn."
              :type :vector
              :tags [:function]
-             :optional? true}
+             :optional? true
+             :added "0.8.0"}
 
             :onyx/medium
             {:doc "Denotes the kind of input or output communication or storage that is being read from or written to (e.g. `:kafka` or `:web-socket`). This is currently does not affect any functionality, and is reserved for the future."

            {:doc "A unique identifier for this window."
             :type :keyword
             :optional? false
             :restrictions ["Must be unique across all Window entries."]}

            :window/task
            {:doc "The task that this window will be applied to."
             :type :keyword
             :optional? false
             :restrictions ["Must name a task in the workflow."]}

            :window/type
            {:doc "The type of Window to use. See the User Guide for what each type means."
             :type :keyword
             :choices [:fixed :sliding :global :session]
             :optional? false}

            :window/aggregation
            {:doc "If this value is a keyword, it is a fully qualified, namespaced keyword pointing to a symbol on the classpath at runtime. This symbol must be a map with keys as further specified by the information model. Onyx comes with a handful of aggregations built in, such as `:onyx.windowing.aggregation/min`. See the User Guide for the full list. Users can also implement their own aggregations.

                  If this value is a vector, it contain two values: a keyword as described above, and another keyword which represents the key to aggregate over."
             :type [:keyword [:keyword]]
             :optional? false}

            :window/window-key
            {:doc "The key of the incoming segments to window over. This key can represent any totally ordered domain, for example `:event-time`."
             :type :any
             :required-when ["`:window/type` is set to `:fixed`"
                             "`:window/type` is set to `:sliding`"
                             "`:window/type` is set to `:session`"]}

            :window/min-key
            {:doc "A globally minimum value that values of `:window/window-key` will never be less than. This is used for calculating materialized aggregates for windows in a space efficient manner."
             :type :integer
             :optional? true
             :default 0}

            :window/session-key
            {:doc "The key of the incoming segments to calculate a session window over. This key can represent any totally ordered domain, e.g. `:event-time`"
             :type :any
             :optional? true}

            :window/range
            {:doc "The span of time, or other totally ordered domain, that this window will capture data within."
             :type [:unit]
             :optional? false
             :required-when ["The `:window/type` is `:fixed` or `:sliding`."]}

            :window/slide
            {:doc "To offset of time, or other totally ordered domain, to wait before starting a new window after the previous window."
             :type [:unit]
             :required-when ["The `:window/type` is `:sliding`."]}

            :window/init
            {:doc "The initial value to be used for the aggregate, if required. Some aggregates require this, such as the Minimum aggregate. Others, such as the Conj aggregate, do not, as empty vector makes a suitable initial value."
             :type :any
             :required-when ["The `:window/aggregation` has no predefined initial value."]}

            :window/timeout-gap
            {:doc "The duration of dormant activity that constitutes a session window being closed."
             :type :unit
             :required-when ["The `window/type` is `:session`."]}

            :window/doc
            {:doc "A docstring for this window."
             :type :string
             :optional? true}}}

   :state-aggregation
   {:summary "Onyx provides the ability to perform stateful updates for segments calculated over windows. For example, a grouping task may accumulate incoming values for a number of keys over windows of 5 minutes."
    :link nil
    :model {:aggregation/init {:doc "Fn (window) to initialise the state."
                               :type :function
                               :optional? true}
            :aggregation/fn {:doc "Fn (state, window, segment) to generate a serializable state machine update."
                             :type :function
                             :optional? false}
            :aggregation/apply-state-update {:doc "Fn (state, entry) to apply state machine update entry to a state."
                                             :type :function
                                             :optional? false}
            :aggregation/super-aggregation-fn {:doc "Fn (state-1, state-2, window) to combine two states in the case of two windows being merged, e.g. session windows."
                                               :type :function
                                               :optional? true}}}
   :trigger-entry
   {:summary "Triggers are a feature that interact with Windows. Windows capture and bucket data over time. Triggers let you release the captured data over a variety stimuli."
    :link nil

            {:doc "The source task from which segments are being sent."
             :type :keyword
             :optional? false
             :restrictions ["Must name a task in the workflow."]
             :added "0.8.0"}

            :flow/to
            {:doc "The destination task where segments will arrive. If set to `:all`, all downstream tasks will receive this segment. If set to `:none`, no downstream tasks will receive this segment. Otherwise it must name a vector of keywords indicating downstream tasks. The order of keywords is irrelevant."
             :type [:keyword [:keyword]]
             :choices [[:any] :all :none]
             :optional? false
             :restrictions ["When the value is a vector of keyword, every keyword must name a task in the workflow."]
             :added "0.8.0"}

            :flow/predicate
            {:doc "When denoted as a keyword, this must be a fully qualified, namespaced keyword pointing to a function on the classpath at runtime. This function takes at least 4 arguments - the Event map, the old segment before `:onyx/fn` was applied, the new segment after `:onyx/fn` was applied, and the sequence of new segments generated by the old semgent. If the old segment generated exactly one segment, and not a sequence of segments, the value of the last parameter will be a collection with only the new segment in it.

                  When denoted as a vector of keywords, the first value in the vector  may either be the keyword `:and`, `:or`, or `:not`, or be a keyword as described above. In the latter case, any subsequent values must be keywords that resolve to keys in the flow condition entries map. The values of these keys are resolved and passed as additional parameters to the function. In the former case, the result of the function (which may again be wrapped with a vector to nest logical operators or parameters), is applied with the designated logical operator. This yields predicate composition."
             :type [:keyword [:keyword]]
             :optional? false
             :added "0.8.0"}

            :flow/exclude-keys
            {:doc "If any of the keys are present in the segment, they will be `dissoc`ed from the segment before it is sent downstream. This is useful when values in the segment are present purely for the purpose of making a decision about which downstream tasks it should be sent to."
             :type [[:keyword]]
             :optional? true
             :added "0.8.0"}

            :flow/short-circuit?
            {:doc "When multiple flow condition entry predicates evaluated to true, the tasks in `:flow/to` are set unioned. If this behavior is undesirable, and you want exactly the tasks in this flow condition's `:flow/to` key to be used, plus any previously matched flow conditions `:flow/to` values. Setting `:flow/short-circuit?` to `true` will force the matcher to stop executing and immediately return with the values that it matched."
             :type :boolean
             :optional? true
             :default false
             :restrictions ["Any entry that has :flow/short-circuit? set to true must come before any entries for an task that have it set to false or nil."]
             :added "0.8.0"}

            :flow/thrown-exception?
            {:doc "If an exception is thrown from an Onyx transformation function, you can capture it from within your flow conditions by setting this value to `true`. If an exception is thrown, only flow conditions with `:flow/thrown-exception?` set to `true` will be evaluated. The value that is normally the segment which is sent to the predicate will be the exception object that was thrown. Note that exceptions don't serialize. This feature is meant to be used in conjunction with Post-transformations and Actions for sending exception values to downstream tasks."
             :type :boolean
             :optional? true
             :default false
             :restrictions ["Exception flow conditions must have `:flow/short-circuit?` set to `true`"]
             :added "0.8.0"}

            :flow/post-transform
            {:doc "A fully qualified, namespaced keyword that points to a function on the classpath at runtime. This function is invoked when an exception is thrown processing a segment in `:onyx/fn` and this flow condition's predicate evaluates to `true`. The function takes 3 parameters - the Event map, the segment that causes the exception to be thrown, and the exception object. The return value of this function is sent to the downstream tasks instead of trying to serialize the exception. The return value must be a segment or sequence of segments, and must serialize."
             :type :keyword
             :optional? true
             :default nil
             :restrictions ["`:flow/thrown-exception?` must be set to `true`."]
             :added "0.8.0"}

            :flow/action
            {:doc "Names a side effect to perform in response to processing this segment. If set to `:retry`, this segment will be immediately, forcibly retried from the root input task from which it eminated. This segment will not be sent to any downstream tasks."
