HsbcJone opened a new pull request, #1386: URL: https://github.com/apache/flink-agents/pull/1386
Linked issue: Closes #1384. Relates to #1378. ### Purpose of change Callers set `retry-wait-interval`, `async.batch.timeout`, and `short-term-memory.state-ttl` with `java.time.Duration` or `datetime.timedelta`. In YAML the value is an integer plus a unit, such as `30 s` or `5 min`. These three framework settings used bare numbers with different units (milliseconds, milliseconds, and seconds). A duration type keeps the unit in the value. This is only the framework slice. Built-in resource and SDK timeout parameters are unchanged. No other numeric framework duration option was found. `AgentConfiguration.get` parses a stored string, or returns a duration the option already holds. `set` writes a canonical string (`60 s` becomes `1 min`) so agent-plan JSON stays text. A positive `async.batch.timeout` is the `ctx.gather` deadline; zero or negative disables it. A positive `short-term-memory.state-ttl` is passed to Flink state TTL; zero or negative leaves TTL off. Chat and decision retries sleep for `interval * 2^(N-1)` and still record whole seconds on `retryWaitSec` and `total_retry_wait_sec`. The `.ms` suffix is dropped from the timeout and TTL keys, and from `ASYNC_BATCH_TIMEOUT_MS` and `SHORT_TERM_MEMORY_STATE_TTL_MS`. `retry-wait-interval` keeps its key. Old keys are rejected rather than read or ignored. A bare number is rejected: treating it as milliseconds would keep the unit ambiguity this change removes. ISO-8601 is not accepted as a second syntax. Values must be whole microseconds so `Duration` and `timedelta` accept the same strings (`1000 ns` is `1 us`; `1 ns` is rejected). `m` means minutes. A leading `-` is kept so the default `-1 ms` timeout still disables the batch timeout. ### Behavioral Semantics | Batch timeout | TTL | Retry wait | Result | | --- | --- | --- | --- | | positive | positive | positive | deadline and state TTL use those durations; retry N waits `interval * 2^(N-1)` | | zero or negative | zero or negative | zero or negative | timeout off, TTL off, retries do not sleep | | positive | zero | positive | timeout on, TTL off, retries wait | | unset | unset | unset | timeout `-1 ms` (off), TTL `0 ms` (off), retry `1 s` | A value cannot be both positive and a disable sentinel. If a removed key is present, construction fails before either key is applied. 1. Keys, types, and defaults match on both sides: `async.batch.timeout` `-1 ms`, `short-term-memory.state-ttl` `0 ms`, `retry-wait-interval` `1 s`. 2. `30 s`, `30s`, `5 min`, `5m`, `1 h`, `1 d`, `1500 ms`, `60 s` (canonical `1 min`), `1000 ns` (canonical `1 us`), `0 s` (canonical `0 ms`), and `-1 ms` parse to the same duration on both sides. 3. A positive batch timeout is the gather deadline. Zero, negative, and the default disable it. 4. A positive TTL is the Flink state TTL. Zero and negative disable it. 5. Retry N sleeps for `interval * 2^(N-1)` when that product is positive. Zero and negative do not sleep. Each reported wait adds only the whole seconds of that sleep. 6. `async.batch.timeout.ms` and `short-term-memory.state-ttl.ms` fail construction and `setStr` / `set_str`. 7. A bare number, a fraction, an unknown unit, or a sub-microsecond value fails with a message that names the value and an example such as `30 s`. Invalid duration text fails when the option is set or read (`IllegalArgumentException` / `ValueError`). Removed keys fail at construction or on write. A duration that overflows, or a retry product that overflows `Duration.multipliedBy` or `toMillis`, raises instead of sleeping a wrapped value. Other unknown keys are still ignored. A file that only sets a removed timeout key now fails to load. ### Tests | Contract | Tests | | --- | --- | | 1. Keys, types, defaults | `DurationFormatTest.optionDefaultsMatchTheDisableSentinels`, `test_option_defaults_match_the_disable_sentinels`, `test_agent_execution_options_include_parallel_tool_call_options`; parity script maps `Duration` to `timedelta` | | 2. Shared parse table | `DurationFormatTest.parsesAndFormats`, `knownValuesMatchDurationFactories`, `test_parse_and_format` | | 3. Timeout disable | `durationStringsKeepDisableSentinelsAndRejectBareNumbers`, `test_duration_strings_keep_disable_sentinels_and_reject_bare_numbers`; gather tests still pass with `-1 ms` and `100 ms` | | 4. TTL disable | same configuration tests; `OperatorStateManager` enables TTL only when `DurationFormat.isPositive` | | 5. Retry sleep and whole seconds | `ChatModelActionRetryTest`, `DecisionModelActionTest`, `test_chat_model_action_retry.py`, `test_decision_model_action.py` | | 6. Removed keys | `removedDurationKeysAreRejected`, `test_removed_duration_keys_are_rejected` | | 7. Invalid values | `DurationFormatTest.rejectsUnusableText`, `rejectsBareNumbersAndSubMicrosecondDurations`, `test_rejects_unusable_text`, `test_rejects_bare_numbers` | Not verified: `check_java_python_config_options_parity.py` was not run (it needs a PyFlink gateway). End-to-end jobs and `ShortTermMemoryTTLIntegrationTest` were compiled, not executed. A sub-second retry was not driven through a model call. <details> <summary>Implementation invariants and supporting evidence</summary> Canonical form uses the largest unit that divides the value: `d`, `h`, `min`, `s`, `ms`, `us`. Zero is `0 ms`. Plan JSON stores that string, not a `Duration` object. Java `set` accepts `Duration` only; YAML and map construction supply the string that `get` parses. Python `set` accepts `timedelta` or the same string. `configuredRetryWait` clamps a negative wait to zero. The gather path passes a positive duration through and passes null when it is not positive. Labels match Flink (`ns`, `us`/`µs`, `ms`, `s`, `min`/`m`, `h`, `d`, plus singular and plural forms). </details> ### API Breaking, before the 1.0 compatibility guarantee. Removed Java constants: `ASYNC_BATCH_TIMEOUT_MS`, `SHORT_TERM_MEMORY_STATE_TTL_MS`. Use `ASYNC_BATCH_TIMEOUT` and `SHORT_TERM_MEMORY_STATE_TTL`. `configuredRetryWaitSec` is `configuredRetryWait` and returns `Duration`. `chatWithRetries` takes a `Duration` backoff. Programmatic callers pass `Duration` or `timedelta`, not a raw number. YAML `retry-wait-interval: 1` must become `1 s`. There is no adapter for the old numbers. Resource and SDK timeout parameters are unchanged. `retryWaitSec`, `total_retry_wait_sec`, and the retry event fields stay whole seconds. ### Documentation - [x] `doc-included` - [ ] `doc-needed` - [ ] `doc-not-needed` ### Was this patch authored or co-authored using generative AI tooling? - [x] Yes - [ ] No Generated-by: Cursor Grok 4.7 (Grok 4.7) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
