Commit Graph

34 Commits

Author SHA1 Message Date
github-actions[bot] a39f132b91 Update versions to 1.19.0-SNAPSHOT and 1.19.0-beta29-SNAPSHOT 2026-07-17 13:42:56 +00:00
github-actions[bot] 66ad5ee6d5 Release versions 1.18.0 and 1.18.0-beta28 2026-07-17 12:34:45 +00:00
Mario Fusco b9e3f27200
Introduce Belief-Desire-Intention (BDI) agentic pattern (#5730)
<!--
Thank you so much for your contribution!

Please fill in all the sections below.
Please open the PR as ready for review (not as a draft), with tests and
documentation already included.
Please note that PRs with breaking changes, or without tests and
documentation, will be rejected.

Please note that PRs will be reviewed based on the priority of the
issues they address.
We ask for your patience. We are doing our best to review your PR as
quickly as possible.
Please refrain from pinging and asking when it will be reviewed. Thank
you for understanding!
-->

## Issue
<!-- Please specify the ID of the issue this PR is addressing. For
example: "Closes #1234" or "Fixes #1234" -->
Closes #

## Change
<!-- Please describe the changes you made. -->


## General checklist
<!-- Please double-check the following points and mark them like this:
[X] -->
- [X] There are no breaking changes (API, behaviour)
- [X] I have added unit and/or integration tests for my change
- [X] The tests cover both positive and negative cases
- [X] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
- [ ] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
- [ ] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)


## Checklist for adding new maven module
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added my new module in the root `pom.xml` and
`langchain4j-bom/pom.xml`


## Checklist for adding new embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreIT` that extends
from either `EmbeddingStoreIT` or `EmbeddingStoreWithFilteringIT`
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreRemovalIT` that
extends from `EmbeddingStoreWithRemovalIT`

## Checklist for changing existing embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have manually verified that the
`{NameOfIntegration}EmbeddingStore` works correctly with the data
persisted using the latest released version of LangChain4j

---------

Co-authored-by: Dmytro Liubarskyi <ljubarskij@gmail.com>
2026-07-14 11:00:31 +02:00
github-actions[bot] 7d7c3349d7 Update versions to 1.18.0-SNAPSHOT and 1.18.0-beta28-SNAPSHOT 2026-06-26 14:49:40 +00:00
github-actions[bot] 207407aec9 Release versions 1.17.0 and 1.17.0-beta27 2026-06-26 13:13:06 +00:00
Eunbin Son 0d16d2884a
fix: unanimousLastWord convergence to normalize verdict token (#5479)
## Issue
<!-- Update with the real issue number once the bug issue is filed. -->
Closes #5478

## Change

Fixes `ConvergenceStrategy.unanimousLastWord()` in
langchain4j-agentic-patterns.

The old extraction `text.substring(text.lastIndexOf(' ') + 1)` splits
only on a literal space, so two realistic debater outputs broke
convergence:
- Trailing punctuation: `"...AGREE."` -> `"AGREE."` != `"AGREE"`.
- Multiline replies: `"Reasoning here.\nAPPROVE"` -> `"here.\nAPPROVE"`.

Both cases misjudge a unanimous debate as non-converged, causing extra
debate rounds (LLM cost and latency).

The fix splits on `\\s+` (covering newlines and tabs) and strips
leading/trailing non-alphanumerics from the final token:

```java
String[] tokens = text.split("\\s+");
String lastWord = tokens[tokens.length - 1]
        .replaceAll("^[^\\p{Alnum}]+|[^\\p{Alnum}]+$", "")
        .toUpperCase();
```

`\\p{Alnum}` is used instead of `\\W` so non-ASCII verdict letters are
preserved. The change stays within the single method; empty input still
yields an empty token, matching prior behavior.

This aligns `unanimousLastWord()` with its sibling `unanimous()`, which
compares whole positions via `Objects.equals`. The strategy (introduced
in #5382) is registered by `DebateExampleIT` and `CodeReviewDebateIT`,
whose prompts end with a one-word verdict.

Added four unit tests to `ConvergenceStrategyTest` (which previously had
no coverage for this method): punctuated, multiline, single-word, and a
negative conflicting-verdict case.

## General checklist
- [X] There are no breaking changes (API, behaviour)
- [X] I have added unit and/or integration tests for my change
- [X] The tests cover both positive and negative cases
- [X] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
- [ ] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
- [ ] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)

Co-authored-by: Mario Fusco <mario.fusco@gmail.com>
2026-06-22 09:13:21 +02:00
Mario Fusco 8b6aeead73
Introduce new Debate agentic pattern (#5382)
<!--
Thank you so much for your contribution!

Please fill in all the sections below.
Please open the PR as a draft initially. Once it is reviewed and
approved, we will ask you to add documentation and examples.
Please note that PRs with breaking changes or without tests will be
rejected.

Please note that PRs will be reviewed based on the priority of the
issues they address.
We ask for your patience. We are doing our best to review your PR as
quickly as possible.
Please refrain from pinging and asking when it will be reviewed. Thank
you for understanding!
-->

## Issue
<!-- Please specify the ID of the issue this PR is addressing. For
example: "Closes #1234" or "Fixes #1234" -->
Closes #

## Change
<!-- Please describe the changes you made. -->


## General checklist
<!-- Please double-check the following points and mark them like this:
[X] -->
- [X] There are no breaking changes (API, behaviour)
- [X] I have added unit and/or integration tests for my change
- [X] The tests cover both positive and negative cases
- [X] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
- [ ] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
<!-- Before adding documentation and example(s) (below), please wait
until the PR is reviewed and approved. -->
- [ ] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)


## Checklist for adding new maven module
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added my new module in the root `pom.xml` and
`langchain4j-bom/pom.xml`


## Checklist for adding new embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreIT` that extends
from either `EmbeddingStoreIT` or `EmbeddingStoreWithFilteringIT`
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreRemovalIT` that
extends from `EmbeddingStoreWithRemovalIT`

## Checklist for changing existing embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have manually verified that the
`{NameOfIntegration}EmbeddingStore` works correctly with the data
persisted using the latest released version of LangChain4j
2026-06-12 11:50:28 +02:00
github-actions[bot] 01de41d641 Update versions to 1.17.0-SNAPSHOT and 1.17.0-beta27-SNAPSHOT 2026-06-06 06:46:38 +00:00
github-actions[bot] cd836845dd Release versions 1.16.0 and 1.16.0-beta26 2026-06-05 15:46:56 +00:00
Mario Fusco 62dc0914ac
Introduce Blackboard agentic pattern (#5243)
<!--
Thank you so much for your contribution!

Please fill in all the sections below.
Please open the PR as a draft initially. Once it is reviewed and
approved, we will ask you to add documentation and examples.
Please note that PRs with breaking changes or without tests will be
rejected.

Please note that PRs will be reviewed based on the priority of the
issues they address.
We ask for your patience. We are doing our best to review your PR as
quickly as possible.
Please refrain from pinging and asking when it will be reviewed. Thank
you for understanding!
-->

## Issue
<!-- Please specify the ID of the issue this PR is addressing. For
example: "Closes #1234" or "Fixes #1234" -->
Closes #

## Change

This pull request introduces the new Blackboard agentic pattern working
as explained in the new section added to the `agents.md` documentation.

It also implements a minor non-breaking improvement to the
`HumanInTheLoop` pattern allowing to optionally declare its input keys,
so that they can be used by agentic patterns using the agent's inputs as
precondition for its activation like GOAP, P2P and this new Blackboard
one.

## General checklist
<!-- Please double-check the following points and mark them like this:
[X] -->
- [X] There are no breaking changes (API, behaviour)
- [X] I have added unit and/or integration tests for my change
- [X] The tests cover both positive and negative cases
- [X] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
- [ ] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
<!-- Before adding documentation and example(s) (below), please wait
until the PR is reviewed and approved. -->
- [X] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)


## Checklist for adding new maven module
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added my new module in the root `pom.xml` and
`langchain4j-bom/pom.xml`


## Checklist for adding new embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreIT` that extends
from either `EmbeddingStoreIT` or `EmbeddingStoreWithFilteringIT`
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreRemovalIT` that
extends from `EmbeddingStoreWithRemovalIT`

## Checklist for changing existing embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have manually verified that the
`{NameOfIntegration}EmbeddingStore` works correctly with the data
persisted using the latest released version of LangChain4j
2026-06-03 12:29:56 +02:00
github-actions[bot] 6185599e37 Update versions to 1.16.0-SNAPSHOT and 1.16.0-beta26-SNAPSHOT 2026-05-15 16:21:14 +00:00
github-actions[bot] d0e54aa006 Release versions 1.15.0 and 1.15.0-beta25 2026-05-15 15:55:12 +00:00
renovate[bot] aade6726e7
chore(deps): update dependency org.jsoup:jsoup to v1.22.2 (#5222)
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [org.jsoup:jsoup](https://jsoup.org/)
([source](https://redirect.github.com/jhy/jsoup)) | `1.18.3` → `1.22.2`
|
![age](https://developer.mend.io/api/mc/badges/age/maven/org.jsoup:jsoup/1.22.2?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/maven/org.jsoup:jsoup/1.18.3/1.22.2?slim=true)
|

---

> [!WARNING]
> Some dependencies could not be looked up. Check the [Dependency
Dashboard](../issues/2069) for more information.

---

### Release Notes

<details>
<summary>jhy/jsoup (org.jsoup:jsoup)</summary>

###
[`v1.22.2`](https://redirect.github.com/jhy/jsoup/blob/HEAD/CHANGES.md#1222-2026-Apr-20)

##### Improvements

- Expanded and clarified `NodeTraversor` support for in-place DOM
rewrites during `NodeVisitor.head()`. Current-node edits such as
`remove`, `replace`, and `unwrap` now recover more predictably, while
traversal stays within the original root subtree. This makes single-pass
tree cleanup and normalization visitors easier to write, for example
when unwrapping presentational elements or replacing text nodes as you
walk the DOM.
[#&#8203;2472](https://redirect.github.com/jhy/jsoup/issues/2472)
- Documentation: clarified that a configured `Cleaner` may be reused
across concurrent threads, and that shared `Safelist` instances should
not be mutated while in use.
[#&#8203;2473](https://redirect.github.com/jhy/jsoup/issues/2473)
- Updated the default HTML `TagSet` for current HTML elements: added
`dialog`, `search`, `picture`, and `slot`; made `ins`, `del`, `button`,
`audio`, `video`, and `canvas` inline by default (`Tag#isInline()`,
aligned to phrasing content in the spec); and added readable
`Element.text()` boundaries for controls and embedded objects via the
new `Tag.TextBoundary` option. This improves pretty-printing and keeps
normalized text from running adjacent words together.
[#&#8203;2493](https://redirect.github.com/jhy/jsoup/pull/2493)

##### Bug Fixes

- Android (R8/ProGuard): added a rule to ignore the optional `re2j`
dependency when not present.
[#&#8203;2459](https://redirect.github.com/jhy/jsoup/issues/2459)
- Fixed a `NodeTraversor` regression in 1.21.2 where removing or
replacing the current node during `head()` could revisit the replacement
node and loop indefinitely. The traversal docs now also clarify which
inserted nodes are visited in the current pass.
[#&#8203;2472](https://redirect.github.com/jhy/jsoup/issues/2472)
- Parsing during charset sniffing no longer fails if an advisory
`available()` call throws `IOException`, as seen on JDK 8
`HttpURLConnection`.
[#&#8203;2474](https://redirect.github.com/jhy/jsoup/issues/2474)
- `Cleaner` no longer makes relative URL attributes in the input
document absolute when cleaning or validating a `Document`. URL
normalization now applies only to the cleaned output, and
`Safelist.isSafeAttribute()` is side effect free.
[#&#8203;2475](https://redirect.github.com/jhy/jsoup/issues/2475)
- `Cleaner` no longer duplicates enforced attributes when the input
`Document` preserves attribute case. A case-variant source attribute is
now replaced by the enforced attribute in the cleaned output.
[#&#8203;2476](https://redirect.github.com/jhy/jsoup/issues/2476)
- If a per-request SOCKS proxy is configured, jsoup now avoids using the
JDK `HttpClient`, because the JDK would silently ignore that proxy and
attempt to connect directly. Those requests now fall back to the legacy
`HttpURLConnection` transport instead, which does support SOCKS.
[#&#8203;2468](https://redirect.github.com/jhy/jsoup/issues/2468)
- `Connection.Response.streamParser()` and `DataUtil.streamParser(Path,
...)` could fail on small inputs without a declared charset, if the
initial 5 KB charset sniff fully consumed the input and closed it before
the stream parse began.
[#&#8203;2483](https://redirect.github.com/jhy/jsoup/issues/2483)
- In XML mode, doctypes with an internal subset, such as `<!DOCTYPE root
[<!ENTITY name "value">]>`, now round-trip correctly. The subset is
preserved as raw text only; entities are not expanded and external DTDs
are not loaded.
[#&#8203;2486](https://redirect.github.com/jhy/jsoup/issues/2486)

##### Build Changes

- Migrated the integration test server from Jetty to Netty, which
actively maintains support for our minimum JDK target (8).
[#&#8203;2491](https://redirect.github.com/jhy/jsoup/pull/2491)

###
[`v1.22.1`](https://redirect.github.com/jhy/jsoup/blob/HEAD/CHANGES.md#1221-2026-Jan-01)

##### Improvements

- Added support for using the `re2j` regular expression engine for
regex-based CSS selectors (e.g. `[attr~=regex]`, `:matches(regex)`),
which ensures linear-time performance for regex evaluation. This allows
safer handling of arbitrary user-supplied query regexes. To enable, add
the `com.google.re2j` dependency to your classpath, e.g.:

```xml
  <dependency>
    <groupId>com.google.re2j</groupId>
    <artifactId>re2j</artifactId>
    <version>1.8</version>
  </dependency>
```

(If you already have that dependency in your classpath, but you want to
keep using the Java regex engine, you can disable re2j via
`System.setProperty("jsoup.useRe2j", "false")`.) You can confirm that
the re2j engine has been enabled correctly by calling
`org.jsoup.helper.Regex.usingRe2j()`.
[#&#8203;2407](https://redirect.github.com/jhy/jsoup/pull/2407)

- Added an instance method `Parser#unescape(String, boolean)` that
unescapes HTML entities using the parser's configuration (e.g. to
support error tracking), complementing the existing static utility
`Parser.unescapeEntities(String, boolean)`.
[#&#8203;2396](https://redirect.github.com/jhy/jsoup/pull/2396)
- Added a configurable maximum parser depth (to limit the number of open
elements on stack) to both HTML and XML parsers. The HTML parser now
defaults to a depth of 512 to match browser behavior, and protect
against unbounded stack growth, while the XML parser keeps unlimited
depth by default, but can opt into a limit via
`org.jsoup.parser.Parser#setMaxDepth`.
[#&#8203;2421](https://redirect.github.com/jhy/jsoup/issues/2421)
- Build: added CI coverage for JDK 25
[#&#8203;2403](https://redirect.github.com/jhy/jsoup/pull/2403)
- Build: added a CI fuzzer for contextual fragment parsing (in addition
to existing full body HTML and XML fuzzers). [oss-fuzz
#&#8203;14041](https://redirect.github.com/google/oss-fuzz/pull/14041)

##### Changes

- Set a removal schedule of jsoup 1.24.1 for previously deprecated APIs.

##### Bug Fixes

- Previously cached child `Elements` of an `Element` were not correctly
invalidated in `Node#replaceWith(Node)`, which could lead to incorrect
results when subsequently calling `Element#children()`.
[#&#8203;2391](https://redirect.github.com/jhy/jsoup/issues/2391)
- Attribute selector values are now compared literally without trimming.
Previously, jsoup trimmed whitespace from selector values and from
element attribute values, which could cause mismatches with browser
behavior (e.g. `[attr=" foo "]`). Now matches align with the CSS
specification and browser engines.
[#&#8203;2380](https://redirect.github.com/jhy/jsoup/issues/2380)
- When using the JDK HttpClient, any system default proxy
(`ProxySelector.getDefault()`) was ignored. Now, the system proxy is
used if a per-request proxy is not set.
[#&#8203;2388](https://redirect.github.com/jhy/jsoup/issues/2388),
[#&#8203;2390](https://redirect.github.com/jhy/jsoup/pull/2390)
- A `ValidationException` could be thrown in the adoption agency
algorithm with particularly broken input. Now logged as a parse error.
[#&#8203;2393](https://redirect.github.com/jhy/jsoup/issues/2393)
- Null characters in the HTML body were not consistently removed; and in
foreign content were not correctly replaced.
[#&#8203;2395](https://redirect.github.com/jhy/jsoup/issues/2395)
- An `IndexOutOfBoundsException` could be thrown when parsing a body
fragment with crafted input. Now logged as a parse error.
[#&#8203;2397](https://redirect.github.com/jhy/jsoup/issues/2397),
[#&#8203;2406](https://redirect.github.com/jhy/jsoup/issues/2406)
- When using StructuralEvaluators (e.g., a `parent child` selector)
across many retained threads, their memoized results could also be
retained, increasing memory use. These results are now cleared
immediately after use, reducing overall memory consumption.
[#&#8203;2411](https://redirect.github.com/jhy/jsoup/issues/2411)
- Cloning a `Parser` now preserves any custom `TagSet` applied to the
parser.
[#&#8203;2422](https://redirect.github.com/jhy/jsoup/issues/2422),
[#&#8203;2423](https://redirect.github.com/jhy/jsoup/pull/2423)
- Custom tags marked as `Tag.Void` now parse and serialize like the
built-in void elements: they no longer consume following content, and
the XML serializer emits the expected self-closing form.
[#&#8203;2425](https://redirect.github.com/jhy/jsoup/issues/2425)
- The `<br>` element is once again classified as an inline tag
(`Tag.isBlock() == false`), matching common developer expectations and
its role as phrasing content in HTML, while pretty-printing and text
extraction continue to treat it as a line break in the rendered output.
[#&#8203;2387](https://redirect.github.com/jhy/jsoup/issues/2387),
[#&#8203;2439](https://redirect.github.com/jhy/jsoup/issues/2439)
- Fixed an intermittent truncation issue when fetching and parsing
remote documents via `Jsoup.connect(url).get()`. On responses without a
charset header, the initial charset sniff could sometimes (depending on
buffering / `available()` behavior) be mistaken for end-of-stream and a
partial parse reused, dropping trailing content.
[#&#8203;2448](https://redirect.github.com/jhy/jsoup/issues/2448)
- `TagSet` copies no longer mutate their template during lazy lookups,
preventing cross-thread `ConcurrentModificationException` when parsing
with shared sessions.
[#&#8203;2453](https://redirect.github.com/jhy/jsoup/pull/2453)
- Fixed parsing of `<svg>` `foreignObject` content nested within a
`<p>`, which could incorrectly move the HTML subtree outside the SVG.
[#&#8203;2452](https://redirect.github.com/jhy/jsoup/issues/2452)

##### Internal Changes

- Deprecated internal helper `org.jsoup.internal.Functions` (for removal
in v1.23.1). This was previously used to support older Android API
levels without full `java.util.function` coverage; jsoup now requires
core library desugaring so this indirection is no longer necessary.
[#&#8203;2412](https://redirect.github.com/jhy/jsoup/pull/2412)

###
[`v1.21.2`](https://redirect.github.com/jhy/jsoup/blob/HEAD/CHANGES.md#1212-2025-Aug-25)

##### Changes

- Deprecated internal (yet visible) methods
`Normalizer#normalize(String, bool)` and
`Attribute#shouldCollapseAttribute(Document.OutputSettings)`. These will
be removed in a future version.
- Deprecated `Connection#sslSocketFactory(SSLSocketFactory)` in favor of
the new `Connection#sslContext(SSLContext)`. Using `sslSocketFactory`
will force the use of the legacy `HttpUrlConnection` implementation,
which does not support HTTP/2.
[#&#8203;2370](https://redirect.github.com/jhy/jsoup/pull/2370)

##### Improvements

- When pretty-printing, if there are consecutive text nodes (via DOM
manipulation), the non-significant whitespace between them will be
collapsed.
[#&#8203;2349](https://redirect.github.com/jhy/jsoup/pull/2349).
- Updated `Connection.Response#statusMessage()` to return a simple
loggable string message (e.g. "OK") when using the `HttpClient`
implementation, which doesn't otherwise return any server-set status
message.
[#&#8203;2356](https://redirect.github.com/jhy/jsoup/issues/2346)
- `Attributes#size()` and `Attributes#isEmpty()` now exclude any
internal attributes (such as user data) from their count. This aligns
with the attributes' serialized output and iterator.
[#&#8203;2369](https://redirect.github.com/jhy/jsoup/pull/2369)
- Added `Connection#sslContext(SSLContext)` to provide a custom SSL
(TLS) context to requests, supporting both the `HttpClient` and the
legacy `HttUrlConnection` implementations.
[#&#8203;2370](https://redirect.github.com/jhy/jsoup/pull/2370)
- Performance optimizations for DOM manipulation methods including when
repeatedly removing an element's first child
(`element.child(0).remove()`, and when using
`Parser#parseBodyFragement()` to parse a large number of direct
children.
[#&#8203;2373](https://redirect.github.com/jhy/jsoup/pull/2373).

##### Bug Fixes

- When parsing from an InputStream and a multibyte character happened to
straddle a buffer boundary, the stream would not be completely read.
[#&#8203;2353](https://redirect.github.com/jhy/jsoup/issues/2353).
- In `NodeTraversor`, if a last child element was removed during the
`head()` call, the parent would be visited twice.
[#&#8203;2355](https://redirect.github.com/jhy/jsoup/issues/2355).
- Cloning an Element that has an Attributes object would add an empty
internal user-data attribute to that clone, which would cause unexpected
results for `Attributes#size()` and `Attributes#isEmpty()`.
[#&#8203;2356](https://redirect.github.com/jhy/jsoup/issues/2356)
- In a multithreaded application where multiple threads are calling
`Element#children()` on the same element concurrently, a race condition
could happen when the method was generating the internal child element
cache (a filtered view of its child nodes). Since concurrent reads of
DOM objects should be threadsafe without external synchronization, this
method has been updated to execute atomically.
[#&#8203;2366](https://redirect.github.com/jhy/jsoup/issues/2366)
- When parsing HTML with svg:script elements in SVG elements, don't
enter the Text insertion mode, but continue to parse as foreign content.
Otherwise, misnested HTML could then cause an IndexOutOfBoundsException.
[#&#8203;2374](https://redirect.github.com/jhy/jsoup/issues/2374)
- Malformed HTML could throw an IndexOutOfBoundsException during the
adoption agency.
[#&#8203;2377](https://redirect.github.com/jhy/jsoup/pull/2377).

###
[`v1.21.1`](https://redirect.github.com/jhy/jsoup/blob/HEAD/CHANGES.md#1211-2025-Jun-23)

##### Changes

- Removed previously deprecated methods.
[#&#8203;2317](https://redirect.github.com/jhy/jsoup/pull/2317)
- Deprecated the `:matchText` pseduo-selector due to its side effects on
the DOM; use the new `::textnode` selector and the
`Element#selectNodes(String css, Class type)` method instead.
[#&#8203;2343](https://redirect.github.com/jhy/jsoup/pull/2343)
- Deprecated `Connection.Response#bufferUp()` in lieu of
`Connection.Response#readFully()` which can throw a checked IOException.
- Deprecated internal methods `Validate#ensureNotNull` (replaced by
typed `Validate#expectNotNull`); protected HTML appenders from Attribute
and Node.
- If you happen to be using any of the deprecated methods, please take
the opportunity now to migrate away from them, as they will be removed
in a future release.

##### Improvements

- Enhanced the `Selector` to support direct matching against nodes such
as comments and text nodes. For example, you can now find an element
that follows a specific comment: `::comment:contains(prices) + p` will
select `p` elements immediately after a `<!-- prices: -->` comment.
Supported types include `::node`, `::leafnode`, `::comment`, `::text`,
`::data`, and `::cdata`. Node contextual selectors like
`::node:contains(text)`, `:matches(regex)`, and `:blank` are also
supported. Introduced `Element#selectNodes(String css)` and
`Element#selectNodes(String css, Class nodeType)` for direct node
selection.
[#&#8203;2324](https://redirect.github.com/jhy/jsoup/pull/2324)
- Added `TagSet#onNewTag(Consumer<Tag> customizer)`: register a callback
that’s invoked for each new or cloned Tag when it’s inserted into the
set. Enables dynamic tweaks of tag options (for example, marking all
custom tags as self-closing, or everything in a given namespace as
preserving whitespace).
- Made `TokenQueue` and `CharacterReader` autocloseable, to ensure that
they will release their buffers back to the buffer pool, for later
reuse.
- Added `Selector#evaluatorOf(String css)`, as a clearer way to obtain
an Evaluator from a CSS query. An alias of `QueryParser.parse(String
css)`.
- Custom tags (defined via the `TagSet`) in a foreign namespace (e.g.
SVG) can be configured to parse as data tags.
- Added `NodeVisitor#traverse(Node)` to simplify node traversal calls
(vs. importing `NodeTraversor`).
- Updated the default user-agent string to improve compatibility.
[#&#8203;2341](https://redirect.github.com/jhy/jsoup/issues/2341)
- The HTML parser now allows the specific text-data type (Data, RcData)
to be customized for known tags. (Previously, that was only supported on
custom tags.)
[#&#8203;2326](https://redirect.github.com/jhy/jsoup/issues/2326).
- Added `Connection#readFully()` as a replacement for
`Connection#bufferUp()` with an explicit IOException. Similarly, added
`Connection#readBody()` over `Connection#body()`. Deprecated
`Connection#bufferUp()`.
[#&#8203;2327](https://redirect.github.com/jhy/jsoup/pull/2327)
- When serializing HTML, the `<` and `>` characters are now escaped in
attributes. This helps prevent a class of mutation XSS attacks.
[#&#8203;2337](https://redirect.github.com/jhy/jsoup/pull/2337)
- Changed `Connection` to prefer using the JDK's HttpClient over
HttpUrlConnection, if available, to enable HTTP/2 support by default.
Users can disable via `-Djsoup.useHttpClient=false`.
[#&#8203;2340](https://redirect.github.com/jhy/jsoup/pull/2340)

##### Bug Fixes

- The contents of a `script` in a `svg` foreign context should be parsed
as script data, not text.
[#&#8203;2320](https://redirect.github.com/jhy/jsoup/issues/2320)
- `Tag#isFormSubmittable()` was updating the Tag's options.
[#&#8203;2323](https://redirect.github.com/jhy/jsoup/issues/2323)
- The HTML pretty-printer would incorrectly trim whitespace when text
followed an inline element in a block element.
[#&#8203;2325](https://redirect.github.com/jhy/jsoup/issues/2325)
- Custom tags with hyphens or other non-letter characters in their names
now work correctly as Data or RcData tags. Their closing tags are now
tokenized properly.
[#&#8203;2332](https://redirect.github.com/jhy/jsoup/issues/2332)
- When cloning an Element, the clone would retain the source's cached
child Element list (if any), which could lead to incorrect results when
modifying the clone's child elements.
[#&#8203;2334](https://redirect.github.com/jhy/jsoup/issues/2334)

###
[`v1.20.1`](https://redirect.github.com/jhy/jsoup/blob/HEAD/CHANGES.md#1201-2025-Apr-29)

##### Changes

- To better follow the HTML5 spec and current browsers, the HTML parser
no longer allows self-closing tags (`<foo />`)
to close HTML elements by default. Foreign content (SVG, MathML), and
content parsed with the XML parser, still
supports self-closing tags. If you need specific HTML tags to support
self-closing, you can register a custom tag via
the `TagSet` configured in `Parser.tagSet()`, using
`Tag#set(Tag.SelfClose)`. Standard void tags (such as `<img>`,
  `<br>`, etc.) continue to behave as usual and are not affected by this
change.
[#&#8203;2300](https://redirect.github.com/jhy/jsoup/issues/2300).
- The following internal components have been **deprecated**. If you do
happen to be using any of these, please take the opportunity now to
migrate away from them, as they will be removed in jsoup 1.21.1.
- `ChangeNotifyingArrayList`, `Document.updateMetaCharsetElement()`,
`Document.updateMetaCharsetElement(boolean)`,
`HtmlTreeBuilder.isContentForTagData(String)`,
`Parser.isContentForTagData(String)`,
`Parser.setTreeBuilder(TreeBuilder)`, `Tag.formatAsBlock()`,
`Tag.isFormListed()`, `TokenQueue.addFirst(String)`,
`TokenQueue.chompTo(String)`, `TokenQueue.chompToIgnoreCase(String)`,
`TokenQueue.consumeToIgnoreCase(String)`, `TokenQueue.consumeWord()`,
`TokenQueue.matchesAny(String...)`

##### Functional Improvements

- Rebuilt the HTML pretty-printer, to simplify and consolidate the
implementation, improve consistency, support custom
Tags, and provide a cleaner path for ongoing improvements. The specific
HTML produced by the pretty-printer may be
different from previous versions.
[#&#8203;2286](https://redirect.github.com/jhy/jsoup/issues/2286).
- Added the ability to define custom tags, and to modify properties of
known tags, via the `TagSet` tag collection.
  Their properties can impact both the parse and how content is
serialized (output as HTML or XML).
[#&#8203;2285](https://redirect.github.com/jhy/jsoup/issues/2285).
- `Element.cssSelector()` will prefer to return shorter selectors by
using ancestor IDs when available and unique. E.g.
`#id > div > p` instead of `html > body > div > div > p`
[#&#8203;2283](https://redirect.github.com/jhy/jsoup/pull/2283).
- Added `Elements.deselect(int index)`, `Elements.deselect(Object o)`,
and `Elements.deselectAll()` methods to remove
elements from the `Elements` list without removing them from the
underlying DOM. Also added `Elements.asList()` method
to get a modifiable list of elements without affecting the DOM.
(Individual Elements remain linked to the
DOM.) [#&#8203;2100](https://redirect.github.com/jhy/jsoup/issues/2100).
- Added support for sending a request body from an InputStream with
`Connection.requestBodyStream(InputStream stream)`.
[#&#8203;1122](https://redirect.github.com/jhy/jsoup/issues/1122).
- The XML parser now supports scoped xmlns: prefix namespace
declarations, and applies the correct namespace to Tags and
Attributes. Also, added `Tag#prefix()`, `Tag#localName()`,
`Attribute#prefix()`, `Attribute#localName()`, and
`Attribute#namespace()` to retrieve these.
[#&#8203;2299](https://redirect.github.com/jhy/jsoup/issues/2299).
- CSS identifiers are now escaped and unescaped correctly to the CSS
spec. `Element#cssSelector()` will emit
appropriately escaped selectors, and the QueryParser supports those.
Added `Selector.escapeCssIdentifier()` and
`Selector.unescapeCssIdentifier()`.
[#&#8203;2297](https://redirect.github.com/jhy/jsoup/pull/2297),
[#&#8203;2305](https://redirect.github.com/jhy/jsoup/pull/2305)

##### Structure and Performance Improvements

- Refactored the CSS `QueryParser` into a clearer recursive descent
parser. [#&#8203;2310](https://redirect.github.com/jhy/jsoup/pull/2310).
- CSS selectors with consecutive combinators (e.g. `div >> p`) will
throw an explicit parse
exception.
[#&#8203;2311](https://redirect.github.com/jhy/jsoup/pull/2311).
- Performance: reduced the shallow size of an Element from 40 to 32
bytes, and the NodeList from 32 to 24.
  [#&#8203;2307](https://redirect.github.com/jhy/jsoup/pull/2307).
- Performance: reduced GC load of new StringBuilders when tokenizing
input
  HTML. [#&#8203;2304](https://redirect.github.com/jhy/jsoup/pull/2304).
- Made `Parser` instances threadsafe, so that inadvertent use of the
same instance across threads will not lead to
  errors. For actual concurrency, use `Parser#newInstance()` per
thread. [#&#8203;2314](https://redirect.github.com/jhy/jsoup/pull/2314).

##### Bug Fixes

- Element names containing characters invalid in XML are now normalized
to valid XML names when
serializing.
[#&#8203;1496](https://redirect.github.com/jhy/jsoup/issues/1496).
- When serializing to XML, characters that are invalid in XML 1.0 should
be removed (not
encoded).
[#&#8203;1743](https://redirect.github.com/jhy/jsoup/issues/1743).
- When converting a `Document` to the W3C DOM in `W3CDom`, elements with
an attribute in an undeclared namespace now
get a declaration of `xmlns:prefix="undefined"`. This allows subsequent
serialization to XML via `W3CDom.asString()`
to succeed.
[#&#8203;2087](https://redirect.github.com/jhy/jsoup/issues/2087).
- The `StreamParser` could emit the final elements of a document twice,
due to how `onNodeCompleted` was fired when closing out the stack.
[#&#8203;2295](https://redirect.github.com/jhy/jsoup/issues/2295).
- When parsing with the XML parser and error tracking enabled, the
trailing `?` in `<?xml version="1.0"?>` would
incorrectly emit an error.
[#&#8203;2298](https://redirect.github.com/jhy/jsoup/issues/2298).
- Calling `Element#cssSelector()` on an element with combining
characters in the class or ID now produces the correct output.
[#&#8203;1984](https://redirect.github.com/jhy/jsoup/issues/1984).

###
[`v1.19.1`](https://redirect.github.com/jhy/jsoup/blob/HEAD/CHANGES.md#1191-2025-Mar-04)

##### Changes

- Added support for **http/2** requests in `Jsoup.connect()`, when
running on Java 11+, via the Java HttpClient
implementation.
[#&#8203;2257](https://redirect.github.com/jhy/jsoup/pull/2257).
- In this version of jsoup, the default is to make requests via the
HttpUrlConnection implementation: use
**`System.setProperty("jsoup.useHttpClient", "true");`** to enable
making requests via the HttpClient instead ,
which will enable http/2 support, if available. This will become the
default in a later version of jsoup, so now is
    a good time to validate it.
- If you are repackaging the jsoup jar in your deployment (i.e. creating
a shaded- or a fat-jar), make sure to specify
    that as a Multi-Release
    JAR.
- If the `HttpClient` impl is not available in your JRE, requests will
continue to be made via
    `HttpURLConnection` (in `http/1.1` mode).
- Updated the minimum Android API Level validation from 10 to **21**. As
with previous jsoup versions, Android
developers need to enable core library desugaring. The minimum Java
version remains Java 8.
  [#&#8203;2173](https://redirect.github.com/jhy/jsoup/pull/2173)
- Removed previously deprecated class: `org.jsoup.UncheckedIOException`
(replace with `java.io.UncheckedIOException`);
moved previously deprecated method `Element Element#forEach(Consumer)`
to
`void Element#forEach(Consumer())`.
[#&#8203;2246](https://redirect.github.com/jhy/jsoup/pull/2246)
- Deprecated the methods `Document#updateMetaCharsetElement(boolean)`
and `Document#updateMetaCharsetElement()`, as the
setting had no effect. When `Document#charset(Charset)` is called, the
document's meta charset or XML encoding
instruction is always set.
[#&#8203;2247](https://redirect.github.com/jhy/jsoup/pull/2247)

##### Improvements

- When cleaning HTML with a `Safelist` that preserves relative links,
the `isValid()` method will now consider these
links valid. Additionally, the enforced attribute `rel=nofollow` will
only be added to external links when configured
in the safelist.
[#&#8203;2245](https://redirect.github.com/jhy/jsoup/pull/2245)
- Added `Element#selectStream(String query)` and
`Element#selectStream(Evaluator)` methods, that return a `Stream` of
matching elements. Elements are evaluated and returned as they are
found, and the stream can be
terminated early.
[#&#8203;2092](https://redirect.github.com/jhy/jsoup/pull/2092)
- `Element` objects now implement `Iterable`, enabling them to be used
in enhanced for loops.
- Added support for fragment parsing from a `Reader` via
`Parser#parseFragmentInput(Reader, Element, String)`.
[#&#8203;1177](https://redirect.github.com/jhy/jsoup/issues/1177)
- Reintroduced CLI executable examples, in `jsoup-examples.jar`.
[#&#8203;1702](https://redirect.github.com/jhy/jsoup/issues/1702)
- Optimized performance of selectors like `#id .class` (and other
similar descendant queries) by around 4.6x, by better
  balancing the Ancestor evaluator's cost function in the query
planner.
[#&#8203;2254](https://redirect.github.com/jhy/jsoup/issues/2254)
- Removed the legacy parsing rules for `<isindex>` tags, which would
autovivify a `form` element with labels. This is no
  longer in the spec.
- Added `Elements.selectFirst(String cssQuery)` and
`Elements.expectFirst(String cssQuery)`, to select the first
matching element from an `Elements` list.
[#&#8203;2263](https://redirect.github.com/jhy/jsoup/pull/2263/)
- When parsing with the XML parser, XML Declarations and Processing
Instructions are directly handled, vs bouncing
through the HTML parser's bogus comment handler. Serialization for
non-doctype declarations no longer end with a
spurious `!`.
[#&#8203;2275](https://redirect.github.com/jhy/jsoup/pull/2275)
- When converting parsed HTML to XML or the W3C DOM, element names
containing `<` are normalized to `_` to ensure valid
XML. For example, `<foo<bar>` becomes `<foo_bar>`, as XML does not allow
`<` in element names, but HTML5
  does. [#&#8203;2276](https://redirect.github.com/jhy/jsoup/pull/2276)
- Reimplemented the HTML5 Adoption Agency Algorithm to the current spec.
This handles mis-nested formating / structural elements.
[#&#8203;2278](https://redirect.github.com/jhy/jsoup/pull/2278)

##### Bug Fixes

- If an element has an `;` in an attribute name, it could not be
converted to a W3C DOM element, and so subsequent XPath
queries could miss that element. Now, the attribute name is more
completely
normalized.
[#&#8203;2244](https://redirect.github.com/jhy/jsoup/issues/2244)
- For backwards compatibility, reverted the internal attribute key for
doctype names to
"name".
[#&#8203;2241](https://redirect.github.com/jhy/jsoup/issues/2241)
- In `Connection`, skip cookies that have no name, rather than throwing
a validation
exception.
[#&#8203;2242](https://redirect.github.com/jhy/jsoup/issues/2242)
- When running on JDK 1.8, the error `java.lang.NoSuchMethodError:
java.nio.ByteBuffer.flip()Ljava/nio/ByteBuffer;`
could be thrown when calling `Response#body()` after parsing from a URL
and the buffer size was
exceeded.
[#&#8203;2250](https://redirect.github.com/jhy/jsoup/pull/2250)
- For backwards compatibility, allow `null` InputStream inputs to
`Jsoup.parse(InputStream stream, ...)`, by returning
an empty `Document`.
[#&#8203;2252](https://redirect.github.com/jhy/jsoup/issues/2252)
- A `template` tag containing an `li` within an open `li` would be
parsed incorrectly, as it was not recognized as a
"special" tag (which have additional processing rules). Also, added the
SVG and MathML namespace tags to the list of
special tags.
[#&#8203;2258](https://redirect.github.com/jhy/jsoup/issues/2258)
- A `template` tag containing a `button` within an open `button` would
be parsed incorrectly, as the "in button scope"
check was not aware of the `template` element. Corrected other instances
including MathML and SVG elements,
also. [#&#8203;2271](https://redirect.github.com/jhy/jsoup/issues/2271)
- An `:nth-child` selector with a negative digit-less step, such as
`:nth-child(-n+2)`, would be parsed incorrectly as a
positive step, and so would not match as expected.
[#&#8203;1147](https://redirect.github.com/jhy/jsoup/issues/1147)
- Calling `doc.charset(charset)` on an empty XML document would throw an
`IndexOutOfBoundsException`.
[#&#8203;2266](https://redirect.github.com/jhy/jsoup/issues/2266)
- Fixed a memory leak when reusing a nested `StructuralEvaluator` (e.g.,
a selector ancestor chain like `A B C`) by
ensuring cache reset calls cascade to inner members.
[#&#8203;2277](https://redirect.github.com/jhy/jsoup/issues/2277)
- Concurrent calls to `doc.clone().append(html)` were not supported.
When a document was cloned, its `Parser` was not cloned but was a
shallow copy of the original parser.
[#&#8203;2281](https://redirect.github.com/jhy/jsoup/issues/2281)

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/langchain4j/langchain4j).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xNzMuNiIsInVwZGF0ZWRJblZlciI6IjQzLjE3My42IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-14 10:09:13 +02:00
renovate[bot] f379321148
chore(deps): update dependency org.apache.pdfbox:pdfbox to v3.0.7 (#5173)
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [org.apache.pdfbox:pdfbox](https://www.apache.org/)
([source](https://svn.apache.org/viewvc/pdfbox/tags/3.0.7/pdfbox)) |
`3.0.5` → `3.0.7` |
![age](https://developer.mend.io/api/mc/badges/age/maven/org.apache.pdfbox:pdfbox/3.0.7?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/maven/org.apache.pdfbox:pdfbox/3.0.5/3.0.7?slim=true)
|

---

> [!WARNING]
> Some dependencies could not be looked up. Check the [Dependency
Dashboard](../issues/2069) for more information.

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/langchain4j/langchain4j).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xNzMuNiIsInVwZGF0ZWRJblZlciI6IjQzLjE3My42IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-12 17:10:07 +02:00
Mario Fusco fc3fb92e8e
Allow an agent to select among different ChatModels + Introduce voting agentic pattern (#5158)
<!--
Thank you so much for your contribution!

Please fill in all the sections below.
Please open the PR as a draft initially. Once it is reviewed and
approved, we will ask you to add documentation and examples.
Please note that PRs with breaking changes or without tests will be
rejected.

Please note that PRs will be reviewed based on the priority of the
issues they address.
We ask for your patience. We are doing our best to review your PR as
quickly as possible.
Please refrain from pinging and asking when it will be reviewed. Thank
you for understanding!
-->

## Issue
<!-- Please specify the ID of the issue this PR is addressing. For
example: "Closes #1234" or "Fixes #1234" -->
Closes #

## Change
<!-- Please describe the changes you made. -->

This pull requests introduces two new features:

- It allows an agent to switch among different models based on the
result of a selector function of the `AgenticScope`
- A new `Voting` agentic pattern that fans out all sub-agents in
parallel and aggregates their results via a pluggable `VotingStrategy`.

Regarding the new voting pattern, I understand that something quite
similar could have been achieved already with the parallel workflow,
plus an output function, but I received multiple feedback on the fact
that it will be nice to have more explicit and use-case driven agentic
patterns implementation and use them as building blocks for more complex
agentic system, so I collected a few proposals and will add a few other
patterns in the near future.

## General checklist
<!-- Please double-check the following points and mark them like this:
[X] -->
- [X] There are no breaking changes (API, behaviour)
- [X] I have added unit and/or integration tests for my change
- [X] The tests cover both positive and negative cases
- [X] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
- [ ] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
<!-- Before adding documentation and example(s) (below), please wait
until the PR is reviewed and approved. -->
- [ ] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)


## Checklist for adding new maven module
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added my new module in the root `pom.xml` and
`langchain4j-bom/pom.xml`


## Checklist for adding new embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreIT` that extends
from either `EmbeddingStoreIT` or `EmbeddingStoreWithFilteringIT`
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreRemovalIT` that
extends from `EmbeddingStoreWithRemovalIT`

## Checklist for changing existing embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have manually verified that the
`{NameOfIntegration}EmbeddingStore` works correctly with the data
persisted using the latest released version of LangChain4j
2026-05-12 10:55:05 +02:00
github-actions[bot] 628ac34c01 Update versions to 1.15.0-SNAPSHOT and 1.15.0-beta25-SNAPSHOT 2026-04-30 18:43:12 +00:00
github-actions[bot] 4917afa297 Release versions 1.14.0 and 1.14.0-beta24 2026-04-30 18:10:30 +00:00
Eric Lin 94137feebf
Fix: NPE when using GOAP with an AgenticScope containing variables not used in the execution graph (#4986) (#4987)
<!--
Thank you so much for your contribution!

Please fill in all the sections below.
Please open the PR as a draft initially. Once it is reviewed and
approved, we will ask you to add documentation and examples.
Please note that PRs with breaking changes or without tests will be
rejected.

Please note that PRs will be reviewed based on the priority of the
issues they address.
We ask for your patience. We are doing our best to review your PR as
quickly as possible.
Please refrain from pinging and asking when it will be reviewed. Thank
you for understanding!
-->

## Issue
<!-- Please specify the ID of the issue this PR is addressing. For
example: "Closes #1234" or "Fixes #1234" -->
Closes #4986 

## Change
<!-- Please describe the changes you made. -->
This PR filters out null precondition nodes that can occur when using
`GoalOrientedSearchGraph` with an `AgenticScope` containing additional
variables that are not directly used in the execution graph (eg. for
observability purposes)

## General checklist
<!-- Please double-check the following points and mark them like this:
[X] -->
- [x] There are no breaking changes (API, behaviour)
- [x] I have added unit and/or integration tests for my change
- [ ] The tests cover both positive and negative cases
- [x] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
- [x] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
<!-- Before adding documentation and example(s) (below), please wait
until the PR is reviewed and approved. -->
- [ ] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)


## Checklist for adding new maven module
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added my new module in the root `pom.xml` and
`langchain4j-bom/pom.xml`


## Checklist for adding new embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreIT` that extends
from either `EmbeddingStoreIT` or `EmbeddingStoreWithFilteringIT`
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreRemovalIT` that
extends from `EmbeddingStoreWithRemovalIT`

## Checklist for changing existing embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have manually verified that the
`{NameOfIntegration}EmbeddingStore` works correctly with the data
persisted using the latest released version of LangChain4j

Co-authored-by: Eric Lin <elin@coursera.org>
Co-authored-by: Mario Fusco <mario.fusco@gmail.com>
2026-04-28 08:31:10 +02:00
github-actions[bot] 4798a89d66 Update versions to 1.14.0-SNAPSHOT and 1.14.0-beta24-SNAPSHOT 2026-04-09 14:41:27 +00:00
github-actions[bot] 759cd9a236 Release versions 1.13.0 and 1.13.0-beta23 2026-04-09 13:07:30 +00:00
Mario Fusco 0b27a96c37
Fix race condition in planner loop (#4868)
<!--
Thank you so much for your contribution!

Please fill in all the sections below.
Please open the PR as a draft initially. Once it is reviewed and
approved, we will ask you to add documentation and examples.
Please note that PRs with breaking changes or without tests will be
rejected.

Please note that PRs will be reviewed based on the priority of the
issues they address.
We ask for your patience. We are doing our best to review your PR as
quickly as possible.
Please refrain from pinging and asking when it will be reviewed. Thank
you for understanding!
-->

## Issue
<!-- Please specify the ID of the issue this PR is addressing. For
example: "Closes #1234" or "Fixes #1234" -->
Closes #4862

## Change

As suggested in the bug report there are two distinct bugs, a more
generic one causing a race condition when multiple agents are executed
in parallel, and another one, still relatively generic, but specifically
triggered by the P2P architecture.
In particular the first bug is a lost-update race on `nextAction`, where
multiple threads calling `onSubagentInvoked` concurrently performed a
non-atomic read-modify-write on the nextAction field, causing follow-up
actions to be silently lost. The fix is simply making that operation
atomic, by wrapping `onSubagentInvoked` body with a `ReentrantLock`
(chosen over synchronized to avoid virtual thread pinning). This fix
also simplifies the implementation of new Planners, making redundant the
user-side lock from `CustomPlannerIT.ParallelInPairsPlanner`, that has
been simplified accodingly.
The second bug is in the fact that `composeActions` drops `done()` in
favor of empty call(). When two parallel agents finish and one returns
done() while the other returns an empty `call()` (no new agents to
schedule), `composeActions` always preferred the non-done action, even
when it carried no work. This caused the planner loop to spin forever
and it has been fixed by adding an `isEmptyCall()` check so empty
`AgentCallActions` are treated as transparent, allowing `done()` to
propagate.

## General checklist
<!-- Please double-check the following points and mark them like this:
[X] -->
- [X] There are no breaking changes (API, behaviour)
- [X] I have added unit and/or integration tests for my change
- [X] The tests cover both positive and negative cases
- [X] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
- [ ] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
<!-- Before adding documentation and example(s) (below), please wait
until the PR is reviewed and approved. -->
- [ ] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)


## Checklist for adding new maven module
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added my new module in the root `pom.xml` and
`langchain4j-bom/pom.xml`


## Checklist for adding new embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreIT` that extends
from either `EmbeddingStoreIT` or `EmbeddingStoreWithFilteringIT`
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreRemovalIT` that
extends from `EmbeddingStoreWithRemovalIT`

## Checklist for changing existing embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have manually verified that the
`{NameOfIntegration}EmbeddingStore` works correctly with the data
persisted using the latest released version of LangChain4j
2026-04-08 09:40:09 +02:00
Mario Fusco 499b5ef21e
Make the execution state of an agentic system persistable and recoverable (#4827)
<!--
Thank you so much for your contribution!

Please fill in all the sections below.
Please open the PR as a draft initially. Once it is reviewed and
approved, we will ask you to add documentation and examples.
Please note that PRs with breaking changes or without tests will be
rejected.

Please note that PRs will be reviewed based on the priority of the
issues they address.
We ask for your patience. We are doing our best to review your PR as
quickly as possible.
Please refrain from pinging and asking when it will be reviewed. Thank
you for understanding!
-->

## Issue
<!-- Please specify the ID of the issue this PR is addressing. For
example: "Closes #1234" or "Fixes #1234" -->
Closes #

## Change
<!-- Please describe the changes you made. -->


## General checklist
<!-- Please double-check the following points and mark them like this:
[X] -->
- [X] There are no breaking changes (API, behaviour)
- [X] I have added unit and/or integration tests for my change
- [X] The tests cover both positive and negative cases
- [X] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
- [ ] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
<!-- Before adding documentation and example(s) (below), please wait
until the PR is reviewed and approved. -->
- [ ] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)


## Checklist for adding new maven module
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added my new module in the root `pom.xml` and
`langchain4j-bom/pom.xml`


## Checklist for adding new embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreIT` that extends
from either `EmbeddingStoreIT` or `EmbeddingStoreWithFilteringIT`
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreRemovalIT` that
extends from `EmbeddingStoreWithRemovalIT`

## Checklist for changing existing embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have manually verified that the
`{NameOfIntegration}EmbeddingStore` works correctly with the data
persisted using the latest released version of LangChain4j
2026-03-31 17:28:03 +02:00
Dmytro Liubarskyi e10abf04d0
Update versions to 1.13.0-SNAPSHOT and 1.13.0-beta23-SNAPSHOT (#4710)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-13 11:39:50 +01:00
Dmytro Liubarskyi c92ea033e4
Update versions to 1.13.0-SNAPSHOT and 1.13.0-beta22-SNAPSHOT (#4666)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-05 17:18:22 +01:00
Dmytro Liubarskyi 336b2accce
Update versions to 1.12.0-SNAPSHOT and 1.12.0-beta20-SNAPSHOT (#4537)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-04 14:27:44 +01:00
Dmytro Liubarskyi 778be1b360
Update versions to 1.11.0-SNAPSHOT and 1.11.0-beta19-SNAPSHOT (#4285)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-12-24 15:38:05 +01:00
Mario Fusco 86b6e1fd15
Make Planners to declare their topology (#4212)
<!--
Thank you so much for your contribution!

Please fill in all the sections below.
Please open the PR as a draft initially. Once it is reviewed and
approved, we will ask you to add documentation and examples.
Please note that PRs with breaking changes or without tests will be
rejected.

Please note that PRs will be reviewed based on the priority of the
issues they address.
We ask for your patience. We are doing our best to review your PR as
quickly as possible.
Please refrain from pinging and asking when it will be reviewed. Thank
you for understanding!
-->

## Issue
<!-- Please specify the ID of the issue this PR is addressing. For
example: "Closes #1234" or "Fixes #1234" -->
Closes #

## Change
The intent of this pull request is to allow `Planner` implementations to
declare their topology among the ones enumerated in
`AgenticSystemTopology`. This should be informative for all users of
that Planner, but also be used by some presentation UI (together with
the list of subagents) to create a nicer and better understandable
diagram of the whole agentic system.

This pull request also makes each agent aware of its parent in the
hierarchy and uses the topology of the agentic system to generate stable
agentIDs.

## General checklist
<!-- Please double-check the following points and mark them like this:
[X] -->
- [x] There are no breaking changes (API, behaviour)
- [x] I have added unit and/or integration tests for my change
- [x] The tests cover both positive and negative cases
- [ ] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
- [ ] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
<!-- Before adding documentation and example(s) (below), please wait
until the PR is reviewed and approved. -->
- [ ] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)


## Checklist for adding new maven module
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added my new module in the root `pom.xml` and
`langchain4j-bom/pom.xml`


## Checklist for adding new embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreIT` that extends
from either `EmbeddingStoreIT` or `EmbeddingStoreWithFilteringIT`
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreRemovalIT` that
extends from `EmbeddingStoreWithRemovalIT`

## Checklist for changing existing embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have manually verified that the
`{NameOfIntegration}EmbeddingStore` works correctly with the data
persisted using the latest released version of LangChain4j

---------

Co-authored-by: Dmytro Liubarskyi <ljubarskij@gmail.com>
2025-12-15 15:23:54 +01:00
Mario Fusco d98e07a2a4
Add observability and monitoring for agentic systems (#4181)
<!--
Thank you so much for your contribution!

Please fill in all the sections below.
Please open the PR as a draft initially. Once it is reviewed and
approved, we will ask you to add documentation and examples.
Please note that PRs with breaking changes or without tests will be
rejected.

Please note that PRs will be reviewed based on the priority of the
issues they address.
We ask for your patience. We are doing our best to review your PR as
quickly as possible.
Please refrain from pinging and asking when it will be reviewed. Thank
you for understanding!
-->

## Issue
<!-- Please specify the ID of the issue this PR is addressing. For
example: "Closes #1234" or "Fixes #1234" -->
Closes #4098

## Change

This pull request provides a first implementation of the observability
features requested here
https://github.com/langchain4j/langchain4j/issues/4098

On top of it also introduces a way to monitor agents as discussed here
https://github.com/langchain4j/langchain4j/discussions/4008

The following explanation, copied from the updated documentation,
provides a recap of how this works.

### Observability

Tracking and logging the agents' invocations can be crucial for
debugging and understanding the aggregate behavior of the whole agentic
system in which those agents participate. For this reason, the
`langchain4j-agentic` module allows to register an `AgenticListener`
through the `listener` method of the agent builders, that is notified of
all agents invocations and their results, and it is defined as follows:

```java
public interface AgenticListener {

    default void beforeAgentInvocation(AgentRequest agentRequest) { }
    default void afterAgentInvocation(AgentResponse agentResponse) { }
    default void onAgentInvocationError(AgentInvocationError agentInvocationError) { }

    default void onAgenticScopeCreated(AgenticScope agenticScope) { }
    default void onAgenticScopeDestroyed(AgenticScope agenticScope) { }
}
```

Note that all methods of this interface have a default empty
implementation, so that it is possible to implement only the methods of
interest. This will also allow to add new methods in future releases
without breaking existing implementations.

For instance the following configuration of the `CreativeWriter` agent
will log to the console when it is invoked and what is the story it
generated.

```java
CreativeWriter creativeWriter = AgenticServices.agentBuilder(CreativeWriter.class)
        .chatModel(baseModel())
        .outputKey("story")
        .listener(new AgenticListener() {
            @Override
            public void beforeAgentInvocation(AgentRequest request) {
                System.out.println("Invoking CreativeWriter with topic: " + request.inputs().get("topic"));
            }
        
            @Override
            public void afterAgentInvocation(AgentResponse response) {
                System.out.println("CreativeWriter generated this story: " + response.output());
            }
        })
        .build();
```

These listener methods receive as argument respectively an
`AgentRequest` and an `AgentResponse` that provide useful information
about the agent invocation, like its name, the inputs it received and
the output it produced, together with the instance of the `AgenticScope`
used for that invocation. Note that these methods are invoked in the
same thread used to also perform the agent invocation, so they are
synchronous with it and should not perform long blocking operations.

Listeners are composable, meaning that you can register multiple
listeners to the same agent, by invoking the `listener` method more than
once, and they will be notified in the order they were registered. They
are also hierarchical, meaning that they are inherited by subagents, so
that if you register a listener to a top level agent, that listener will
also be notified of the invocations of all its subagents at any level
and composed with all listeners that these subagents could have
registered on their own.

### Monitoring

Leveraging the observability features provided by the `AgenticListener`
interface, the `langchain4j-agentic` module also provides a built-in
implementation of this interface, named `AgenticMonitor`, having the
goal of recording all agents invocations in an in-memory tree structure,
allowing to inspect the sequence of invocations and their results during
or after the execution of the agentic system. This monitor can be
registered as a listener to the root agent of the agentic system using
the `listener` method of the agent builder.

To provide a more comprehensive example, let's reconsider the loop
workflow intended to generate and iteratively refine a story until it
meets the required style quality, and register a few listeners on it,
including an `AgenticMonitor`.

```java
AgenticMonitor monitor = new AgenticMonitor();

CreativeWriter creativeWriter = AgenticServices.agentBuilder(CreativeWriter.class)
        .listener(new AgenticListener() {
            @Override
            public void beforeAgentInvocation(AgentRequest request) {
                System.out.println("Invoking CreativeWriter with topic: " + request.inputs().get("topic"));
            }
        })
        .chatModel(baseModel())
        .outputKey("story")
        .build();

StyleEditor styleEditor = AgenticServices.agentBuilder(StyleEditor.class)
        .chatModel(baseModel())
        .outputKey("story")
        .build();

StyleScorer styleScorer = AgenticServices.agentBuilder(StyleScorer.class)
        .name("styleScorer")
        .chatModel(baseModel())
        .outputKey("score")
        .build();

UntypedAgent styleReviewLoop = AgenticServices.loopBuilder()
        .subAgents(styleScorer, styleEditor)
        .maxIterations(5)
        .exitCondition(agenticScope -> agenticScope.readState("score", 0.0) >= 0.8)
        .build();

UntypedAgent styledWriter = AgenticServices.sequenceBuilder()
        .subAgents(creativeWriter, styleReviewLoop)
        .listener(new AgenticListener() {
            @Override
            public void afterAgentInvocation(AgentResponse response) {
                if (response.agentName().equals("styleScorer")) {
                    System.out.println("Current score: " + response.output());
                }
            }
        })
        .listener(monitor)
        .outputKey("story")
        .build();
```

Here a first listener is registered directly on the `creativeWriter`
agent, so that it logs the request topic for the story to be generated
only when that agent is invoked. A second listener is registered on the
top level `styledWriter` agent, so that it will be also invoked for all
subagents in the hierarchy of that agent at any level. That is why the
`afterAgentInvocation` method of that listener checks if the agent being
invoked is the `styleScorer`, and only in that case it logs the current
score assigned to the style of the generated story.

Finally, the `AgenticMonitor` instance is also registered, and
automatically composed with the other 2 listeners, as a further listener
to the `styledWriter` top level agent, so that it can track all agents
invocations in the whole agentic system.

When invoking the `styledWriter` agent as follows:

```java
Map<String, Object> input = Map.of(
        "topic", "dragons and wizards",
        "style", "comedy");
String story = styledWriter.invoke(input);
```

the `AgenticMonitor` records all agents invocations in a tree structure
that also keeps track of the start time, finish time, duration, inputs
and output of each agent call. At this point it is possible to retrieve
the recorded executions from the monitor and for instance print it to
the console for inspection.

```java
MonitoredExecution execution = monitor.successfulExecutions().get(0);
System.out.println(execution);
```

so it will reveal the nested sequence of agents invocations necessary to
generate and refine the story, like it follows:

```
AgentCall{agent=Sequential, startTime=2025-12-04T17:23:45.684601233, finishTime=2025-12-04T17:25:31.310476077, duration=105625 ms, inputs={style=comedy, topic=dragons and wiz...}, output=In the shadowy ...}
|=> AgentCall{agent=generateStory, startTime=2025-12-04T17:23:45.687031946, finishTime=2025-12-04T17:23:53.216629832, duration=7529 ms, inputs={topic=dragons and wiz...}, output=In the shadowed...}
|=> AgentCall{agent=reviewLoop, startTime=2025-12-04T17:23:53.218004760, finishTime=2025-12-04T17:25:31.310442197, duration=98092 ms, inputs={score=0.85, topic=dragons and wiz..., style=comedy, story=In the shadowy ...}, output=null}
    |=> AgentCall{agent=scoreStyle, startTime=2025-12-04T17:23:53.218606335, finishTime=2025-12-04T17:23:58.900747685, duration=5682 ms, inputs={style=comedy, story=In the shadowed...}, output=0.25}
    |=> AgentCall{agent=editStory, startTime=2025-12-04T17:23:58.901041911, finishTime=2025-12-04T17:24:58.130857588, duration=59229 ms, inputs={style=comedy, story=In the shadowed...}, output=In the shadowy ...}
    |=> AgentCall{agent=scoreStyle, startTime=2025-12-04T17:24:58.130980855, finishTime=2025-12-04T17:25:31.310076714, duration=33179 ms, inputs={style=comedy, story=In the shadowy ...}, output=0.85}
```

## General checklist
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] There are no breaking changes (API, behaviour)
- [X] I have added unit and/or integration tests for my change
- [X] The tests cover both positive and negative cases
- [X] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
- [ ] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
<!-- Before adding documentation and example(s) (below), please wait
until the PR is reviewed and approved. -->
- [ ] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)


## Checklist for adding new maven module
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added my new module in the root `pom.xml` and
`langchain4j-bom/pom.xml`


## Checklist for adding new embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreIT` that extends
from either `EmbeddingStoreIT` or `EmbeddingStoreWithFilteringIT`
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreRemovalIT` that
extends from `EmbeddingStoreWithRemovalIT`

## Checklist for changing existing embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have manually verified that the
`{NameOfIntegration}EmbeddingStore` works correctly with the data
persisted using the latest released version of LangChain4j
2025-12-11 16:24:24 +01:00
Dmytro Liubarskyi af184e7756 ITs: added missing @EnabledIfEnvironmentVariable annotations 2025-12-11 10:18:49 +01:00
Dmytro Liubarskyi ca6097e35d
Update versions to 1.10.0-SNAPSHOT and 1.10.0-beta18-SNAPSHOT (#4152)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-11-28 12:21:30 +01:00
Dmytro Liubarskyi bc0801a4df
Update versions to 1.10.0-SNAPSHOT and 1.10.0-beta17-SNAPSHOT (#4140)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-11-26 17:38:36 +01:00
Mario Fusco ce762b8cc5
Fix test for GOAP planner (#4103)
<!--
Thank you so much for your contribution!

Please fill in all the sections below.
Please open the PR as a draft initially. Once it is reviewed and
approved, we will ask you to add documentation and examples.
Please note that PRs with breaking changes or without tests will be
rejected.

Please note that PRs will be reviewed based on the priority of the
issues they address.
We ask for your patience. We are doing our best to review your PR as
quickly as possible.
Please refrain from pinging and asking when it will be reviewed. Thank
you for understanding!
-->

## Issue
<!-- Please specify the ID of the issue this PR is addressing. For
example: "Closes #1234" or "Fixes #1234" -->
Closes #

## Change
<!-- Please describe the changes you made. -->


## General checklist
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] There are no breaking changes (API, behaviour)
- [ ] I have added unit and/or integration tests for my change
- [ ] The tests cover both positive and negative cases
- [ ] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
- [ ] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
<!-- Before adding documentation and example(s) (below), please wait
until the PR is reviewed and approved. -->
- [ ] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)


## Checklist for adding new maven module
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added my new module in the root `pom.xml` and
`langchain4j-bom/pom.xml`


## Checklist for adding new embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreIT` that extends
from either `EmbeddingStoreIT` or `EmbeddingStoreWithFilteringIT`
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreRemovalIT` that
extends from `EmbeddingStoreWithRemovalIT`

## Checklist for changing existing embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have manually verified that the
`{NameOfIntegration}EmbeddingStore` works correctly with the data
persisted using the latest released version of LangChain4j
2025-11-21 11:31:32 +01:00
Dmytro Liubarskyi 2448b82a01 temporarily disabled infinite loop agentic test 2025-11-18 10:49:38 +01:00
Mario Fusco 0f8e3861dc
Introduce a generic agentic planner and reimplement all agentic patterns through it (#3929)
## Custom agentic patterns

The `langchain4j-agentic` module provides out-of-the-box a few useful
agentic pattern, but what if none of them fit the specific needs of your
application? In this case it is possible to create your own custom
pattern, that orchestrates the interactions among a set of subagents in
a way that is tailored to your requirements.

In more details an agentic pattern is simply the specification of an
execution plan for the subagents that it coordinates. This plan can be
defined by implementing the following `Planner` interface:

```java
public interface Planner {

    default void init(AgenticScope agenticScope, AgentInstance plannerAgent, List<AgentInstance> subagents) { }

    default Action firstAction(AgenticScope agenticScope) {
        return nextAction(agenticScope, null);
    }

    Action nextAction(AgenticScope agenticScope, AgentExecution previousAgentExecution);
}
```

This interface has three methods: `init`, `firstAction`, and
`nextAction`. The `init` method is called once at the beginning of the
execution, and can be used to initialize any state or data structures
needed by the planner. The `firstAction` method is called to determine
the first action to be taken by the agentic pattern, while the
`nextAction` method is called after each agent execution to determine
the next action to be taken based on the current state of the
`AgenticScope` and the result of the previous agent execution.

The `Action` class returned by the `firstAction` and `nextAction`
methods represents the next step to be taken by the agentic pattern, and
can be one either a list of one or more subagents to be called next, or
a signal that the execution has been completed. If the action specifies
only one subagent invocation, then it will be executed sequentially, and
in the same thread that is executing the planner itself, while if there
are more than one, they will be executed in parallel using the provided
`Executor` or the LangChain4j default one.

All the built-in agentic patterns are also written in terms of this
`Planner` abstraction and giving a look at their implementation can
clarify how this works and be a good starting point to create your own
custom patterns. For instance the parallel workflow is probably the
simplest of those implementation, and it is defined as follows:

```java
public class ParallelPlanner implements Planner {

    private List<AgentInstance> agents;

    @Override
    public void init(AgenticScope agenticScope, AgentInstance plannerAgent, List<AgentInstance> subagents) {
        this.agents = subagents;
    }

    @Override
    public Action firstAction(AgenticScope agenticScope) {
        return call(agents);
    }

    @Override
    public Action nextAction(final AgenticScope agenticScope, final AgentExecution previousAgentExecution) {
        return done();
    }
}
```

Here the `init` method simply stores the list of subagents with which
the parallel workflow has been configured, while the `firstAction`
method returns an action that calls all those agents in parallel. Once
this parallel execution is completed, there isn't any other action to be
taken, so the `nextAction` method simply returns `done()` used to signal
the termination of the execution.

The `Planner` implementing the sequential workflow is only slightly more
complex, as it needs to keep track of the next subagent to be invoked
using an internal cursor, and then return the appropriate action in the
`nextAction` method or signal the termination of the execution when all
subagents have been invoked.

```java
public class SequentialPlanner implements Planner {

    private List<AgentInstance> agents;
    private int agentCursor = 0;

    @Override
    public void init(AgenticScope agenticScope, AgentInstance plannerAgent, List<AgentInstance> subagents) {
        this.agents = subagents;
    }

    @Override
    public Action nextAction(AgenticScope agenticScope, AgentExecution previousAgentExecution) {
        return agentCursor >= agents.size() ? done() : call(agents.get(agentCursor++));
    }
}
```

To understand how to define an agentic system from a planner
implementation, it is possible, for example, to create an instance of
the formerly discussed sequential workflow generating a novel for a
topic and then editing it for a specific style and audience, as it
follows:

```java
UntypedAgent novelCreator = AgenticServices.plannerBuilder()
                .subAgents(creativeWriter, audienceEditor, styleEditor)
                .outputKey("story")
                .planner(SequentialPlanner::new)
                .build();
```

which is totally equivalent to use the dedicated API for sequential
workflows:

```java
UntypedAgent novelCreator = AgenticServices.sequenceBuilder()
                .subAgents(creativeWriter, audienceEditor, styleEditor)
                .outputKey("story")
                .build();
```

The `plannerBuilder()` method is similar to all other agent builders,
with the only difference that it requires to provide a
`Supplier<Planner>` returning a new instance of the specific planner to
be used by this agentic system. Of course an agentic system implementing
a custom planner can be seamlessly combined with any other of the
agentic pattern offered out-of-the-box by the `langchain4j-agentic`
module.

Having clarified how this `Planner` abstraction works, it is now
possible to create your own custom agentic patterns by implementing it.
The following sections provide two examples of custom patterns that can
be useful in different scenarios.

### Goal oriented agentic pattern

The workflow patterns and the supervisor agent represents the two
extremes of the spectrum of possible agentic systems: the former is
completely deterministic and rigid, forcing to decide in advance the
sequence of agents to be invoked, while the latter is completely
flexible and adaptive, but delegates the decision of the sequence of
agents to be invoked to a non-deterministic LLM. However, there are
cases where a middle ground between these two extremes can be more
appropriate, allowing agents to work towards a specific goal in a
relatively flexible way, but also determining how these agents should be
invoked in an algorithmic way.

In order to put this approach in practice, not only the whole agentic
system needs to define a goal, but also each subagent needs to declare
its own pre and postconditions. This is necessary to calculate the
sequence of agent invocations that lead to the achievement of the goal
in the fastest possible way. However, all this information are
implicitly already present in the agentic system, as those pre and
postconditions are nothing else than the required inputs and produced
outputs of each agent, and the final goal is simply the desired outputs
of the whole agentic system.

Following this idea, it is possible to calculate a dependency graph of
all the subagents participating in the agentic system, and then to
implement a `Planner` that is capable of analyzing the initial state of
the `AgenticScope`, comparing it with the desired goal, and then using
that graph to determine the sequence of agent invocations that can lead
to the achievement of that goal.

```java
public class GoalOrientedPlanner implements Planner {

    private String goal;

    private GoalOrientedSearchGraph graph;
    private List<AgentInstance> path;

    private int agentCursor = 0;

    @Override
    public void init(AgenticScope agenticScope, AgentInstance plannerAgent, List<AgentInstance> subagents) {
        this.goal = plannerAgent.outputKey();
        this.graph = new GoalOrientedSearchGraph(subagents);
    }

    @Override
    public Action firstAction(AgenticScope agenticScope) {
        path = graph.search(agenticScope.state().keySet(), goal);
        if (path.isEmpty()) {
            throw new IllegalStateException("No path found for goal: " + goal);
        }
        return call(path.get(agentCursor++));
    }

    @Override
    public Action nextAction(AgenticScope agenticScope, AgentExecution previousAgentExecution) {
        return agentCursor >= path.size() ? done() : call(path.get(agentCursor++));
    }
}
```

As anticipated, here the goal coincides with the final output of the
planner-based agentic pattern itself, while the path from the initial
state to the goal is calculated using a `GoalOrientedSearchGraph`, that
is built analyzing the input and output keys of all subagents. The
sequence of agents to be invoked is then calculated as the shortest path
on that graph from the current state to the desired goal.

To give a practical example of how this works, let's try to build a
goal-oriented agentic system that can extract the name and zodiac sign
of a person from a prompt, generate the horoscope for that sign, look
for a related story on the internet and finally create a nice writeup
combining all this information. We can achieve this set of tasks by
using the following 5 agents:

```java
public interface HoroscopeGenerator {
    @SystemMessage(
            """
            You are an astrologist that generates horoscopes based on the user's name and zodiac sign.
            """)
    @UserMessage("""
            Generate the horoscope for {{person}} who is a {{sign}}.
            """)
    @Agent("An astrologist that generates horoscopes based on the user's name and zodiac sign.")
    String horoscope(@V("person") Person person, @V("sign") Sign sign);
}

public interface PersonExtractor {

    @UserMessage("""
            Extract a person from the following prompt: {{prompt}}
            """)
    @Agent("Extract a person from user's prompt")
    Person extractPerson(@V("prompt") String prompt);
}

public interface SignExtractor {

    @UserMessage("""
            Extract the zodiac sign of a person from the following prompt: {{prompt}}
            """)
    @Agent("Extract a person from user's prompt")
    Sign extractSign(@V("prompt") String prompt);
}

public interface Writer {
    @UserMessage("""
            Create an amusing writeup for {{person}} based on the following:
            - their horoscope: {{horoscope}}
            - a current news story: {{story}}
            """)
    @Agent("Create an amusing writeup for the target person based on their horoscope and current news stories")
    String write(@V("person") Person person, @V("horoscope") String horoscope, @V("story") String story);
}

public interface StoryFinder {

    @SystemMessage("""
            You're a story finder, use the provided web search tools, calling it once and only once,
            to find a fictional and funny story on the internet about the user provided topic.
            """)
    @UserMessage("""
            Find a story on the internet for {{person}} who has the following horoscope: {{horoscope}}.
            """)
    @Agent("Find a story on the internet for a given person with a given horoscope")
    String findStory(@V("person") Person person, @V("horoscope") String horoscope);
}
```

Leveraging the `GoalOrientedPlanner` developed before, these agents can
be combined in a goal-oriented agentic system as follows:

```java
HoroscopeGenerator horoscopeGenerator = AgenticServices.agentBuilder(HoroscopeGenerator.class)
        .chatModel(baseModel())
        .outputKey("horoscope")
        .build();

PersonExtractor personExtractor = AgenticServices.agentBuilder(PersonExtractor.class)
        .chatModel(baseModel())
        .outputKey("person")
        .build();

SignExtractor signExtractor = AgenticServices.agentBuilder(SignExtractor.class)
        .chatModel(baseModel())
        .outputKey("sign")
        .build();

Writer writer = AgenticServices.agentBuilder(Writer.class)
        .chatModel(baseModel())
        .outputKey("writeup")
        .build();

StoryFinder storyFinder = AgenticServices.agentBuilder(StoryFinder.class)
        .chatModel(baseModel())
        .tools(new WebSearchTool())
        .outputKey("story")
        .build();

UntypedAgent horoscopeAgent = AgenticServices.plannerBuilder()
        .subAgents(horoscopeGenerator, personExtractor, signExtractor, writer, storyFinder)
        .outputKey("writeup")
        .planner(GoalOrientedPlanner::new)
        .build();
```

As anticipated, the overall goal of this agentic system is to produce a
`writeup` which is also the output key of the GOAP-based planner itself.
Taking into account the inputs and outputs of all subagents, the
dependency graph built by the `GoalOrientedSearchGraph` will look like
this:

<img width="970" height="871" alt="goap"
src="https://github.com/user-attachments/assets/0249b79f-9839-427c-9548-58774c371c30"
/>

When invoking this agentic system with a prompt like "My name is Mario
and my zodiac sign is pisces"

```java
Map<String, Object> input = Map.of("prompt", "My name is Mario and my zodiac sign is pisces");
String writeup = horoscopeAgent.invoke(input);
```

the `GoalOrientedPlanner` will analyze the initial state of the
`AgenticScope`, that contains only the `prompt` variable, and then it
will calculate the shortest path on the dependency graph from that
initial state to the desired goal, which is the `writeup`, so that the
resulting sequence of agent invocations will be:

```
Agents path sequence: [extractPerson, extractSign, horoscope, findStory, write]
```
Note that, as anticipated, this goal-oriented agentic pattern can be
mixed and combined with any other of the existing agentic patterns. For
instance this possibility can be used to overcome an evident limitation
of this approach that, being optimized to reach a specific goal
following the shortest possible path, structurally doesn't allow loops,
so in some cases it could be useful to have a loop agentic pattern as a
subagent of this goal-oriented one.

### Peer-to-peer agentic pattern

All the agentic system discussed up to this point are based on a
centralized and hierarchical architecture. In fact all the workflow
patterns had a well-defined top-level agent coordinating the activities
of multiple sub-agents in a programmatically predetermined way. Even the
supervisor pattern, which is more flexible and dynamic thanks to the
presence of its LLM-based planner agent, still relies on a coordinator
agent that controls the interactions among the various sub-agents. This
typology of architectures are suitable for many applications and
scenarios, but they can also have some limitations, especially in terms
of scalability and fault tolerance. This is why we may want to offer an
alternative peer-to-peer approach for multi-agent systems, that can
overcome these limitations by adopting a more decentralized and
distributed strategy.

In a peer-to-peer agentic systems there isn't any top level agent, and
all agents are equal peers that are coordinated through the state of the
`AgenticScope`. In particular, an agent is triggered by the presence of
its own required inputs as state variables in the `AgenticScope`.
Subsequently, a change in one or more of those variables, produced by
the output of a different agent, can retrigger the invocation of that
agent again. The process terminates either when the `AgenticScope`
reaches a stable state and no agent can be invoked anymore, or when the
predefined exit condition is satisfied, or when a maximum number of
agent invocations has been reached. A `Planner` implementation that
realizes this peer-to-peer agentic pattern could be written as it
follows:

```java
public class P2PPlanner implements Planner {

    private final int maxAgentsInvocations;
    private final BiPredicate<AgenticScope, Integer> exitCondition;

    private int invocationCounter = 0;
    private Map<String, AgentActivator> agentActivators;

    public P2PPlanner(int maxAgentsInvocations, BiPredicate<AgenticScope, Integer> exitCondition) {
        this(null, maxAgentsInvocations, exitCondition);
    }

    @Override
    public void init(AgenticScope agenticScope, AgentInstance plannerAgent, List<AgentInstance> subagents) {
        this.agentActivators = subagents.stream().collect(toMap(AgentInstance::name, AgentActivator::new));
    }

    @Override
    public Action nextAction(AgenticScope agenticScope, AgentExecution previousAgentExecution) {
        if (terminated(agenticScope)) {
            return done();
        }

        AgentActivator lastExecutedAgent = agentActivators.get(previousAgentExecution.agentSpec().uniqueName());
        lastExecutedAgent.finishExecution();
        agentActivators.values().forEach(a -> a.onStateChanged(lastExecutedAgent.agent.outputKey()));

        AgentInstance[] agentsToCall = agentActivators.values().stream()
                .filter(agentActivator -> agentActivator.canActivate(agenticScope))
                .peek(AgentActivator::startExecution)
                .map(AgentActivator::agent)
                .toArray(AgentInstance[]::new);
        invocationCounter += agentsToCall.length;
        return call(agentsToCall);
    }

    private boolean terminated(AgenticScope agenticScope) {
        return invocationCounter > maxAgentsInvocations || exitCondition.test(agenticScope, invocationCounter);
    }
}
```

Here the `P2PPlanner` keeps track of the number of agent invocations
performed so far, and uses an `AgentActivator` for each subagent to
determine if it can be invoked based on the current state of the
`AgenticScope`. The `nextAction` method checks if the exit condition has
been met or if the maximum number of invocations has been reached, and
if not, it identifies all agents that can be activated based on the
current state, marks them as started, and returns an action to call
them.

To give a practical example of how this works let's try to build a
peer-to-peer agentic system that can perform a scientific research and
formulate new hypothesis on a given topic, so that the API of this
service could be something like:

```java
public interface ResearchAgent {

    @Agent("Conduct research on a given topic")
    String research(@V("topic") String topic);
}
```

To this purpose the following 5 agents can be defined:

```java
public interface LiteratureAgent {

    @SystemMessage("Search for scientific literature on the given topic and return a summary of the findings.")
    @UserMessage("""
            You are a scientific literature search agent.
            Your task is to find relevant scientific papers on the topic provided by the user and summarize them.
            Use the provided tool to search for scientific papers and return a summary of your findings.
            The topic is: {{topic}}
            """)
    @Agent("Search for scientific literature on a given topic")
    String searchLiterature(@V("topic") String topic);
}

public interface HypothesisAgent {

    @SystemMessage("Based on the research findings, formulate a clear and concise hypothesis related to the given topic.")
    @UserMessage("""
            You are a hypothesis formulation agent.
            Your task is to formulate a clear and concise hypothesis based on the research findings provided by the user.
            The topic is: {{topic}}
            The research findings are: {{researchFindings}}
            """)
    @Agent("Formulate hypothesis around a give topic based on research findings")
    String makeHypothesis(@V("topic") String topic, @V("researchFindings") String researchFindings);
}

public interface CriticAgent {

    @SystemMessage("Critically evaluate the given hypothesis related to the specified topic. Provide constructive feedback and suggest improvements if necessary.")
    @UserMessage("""
            You are a critical evaluation agent.
            Your task is to critically evaluate the hypothesis provided by the user in relation to the specified topic.
            Provide constructive feedback and suggest improvements if necessary.
            If you need to, you can also perform additional research to validate or confute the hypothesis using the provided tool.
            The topic is: {{topic}}
            The hypothesis is: {{hypothesis}}
            """)
    @Agent("Critically evaluate a hypothesis related to a given topic")
    String criticHypothesis(@V("topic") String topic, @V("hypothesis") String hypothesis);
}

public interface ValidationAgent {

    @SystemMessage("Validate the provided hypothesis on the given topic based on the critique provided.")
    @UserMessage("""
            You are a validation agent.
            Your task is to validate the hypothesis provided by the user in relation to the specified topic based on the critique provided.
            Validate the provided hypothesis, either confirming it or reformulating a different hypothesis based on the critique.
            The topic is: {{topic}}
            The hypothesis is: {{hypothesis}}
            The critique is: {{critique}}
            """)
    @Agent("Validate a hypothesis based on a given topic and critique")
    String validateHypothesis(@V("topic") String topic, @V("hypothesis") String hypothesis, @V("critique") String critique);
}

public interface ScorerAgent {

    @SystemMessage("Score the provided hypothesis on the given topic based on the critique provided.")
    @UserMessage("""
            You are a scoring agent.
            Your task is to score the hypothesis provided by the user in relation to the specified topic based on the critique provided.
            Score the provided hypothesis on a scale from 0.0 to 1.0, where 0.0 means the hypothesis is completely invalid and 1.0 means the hypothesis is fully valid.
            The topic is: {{topic}}
            The hypothesis is: {{hypothesis}}
            The critique is: {{critique}}
            """)
    @Agent("Score a hypothesis based on a given topic and critique")
    double scoreHypothesis(@V("topic") String topic, @V("hypothesis") String hypothesis, @V("critique") String critique);
}
```

These agents will be all provided with a tool capable of performing
research on scientific literature, for instance downloading academic
papers from arXiv, and then added to the P2P agentic system:

```java
ArxivCrawler arxivCrawler = new ArxivCrawler();

LiteratureAgent literatureAgent = AgenticServices.agentBuilder(LiteratureAgent.class)
        .chatModel(baseModel())
        .tools(arxivCrawler)
        .outputKey("researchFindings")
        .build();
HypothesisAgent hypothesisAgent = AgenticServices.agentBuilder(HypothesisAgent.class)
        .chatModel(baseModel())
        .tools(arxivCrawler)
        .outputKey("hypothesis")
        .build();
CriticAgent criticAgent = AgenticServices.agentBuilder(CriticAgent.class)
        .chatModel(baseModel())
        .tools(arxivCrawler)
        .outputKey("critique")
        .build();
ValidationAgent validationAgent = AgenticServices.agentBuilder(ValidationAgent.class)
        .chatModel(baseModel())
        .tools(arxivCrawler)
        .outputKey("hypothesis")
        .build();
ScorerAgent scorerAgent = AgenticServices.agentBuilder(ScorerAgent.class)
        .chatModel(baseModel())
        .tools(arxivCrawler)
        .outputKey("score")
        .build();

ResearchAgent researcher = AgenticServices.plannerBuilder(ResearchAgent.class)
        .subAgents(literatureAgent, hypothesisAgent, criticAgent, validationAgent, scorerAgent)
        .outputKey("hypothesis")
        .planner(() -> new P2PPlanner(10, agenticScope -> {
            if (!agenticScope.hasState("score")) {
                return false;
            }
            double score = agenticScope.readState("score", 0.0);
            System.out.println("Current hypothesis score: " + score);
            return score >= 0.85;
        }))
        .build();

String hypothesis = researcher.research("black holes");
```

With this configuration the `researcher` p2p coordinator is passed with
the topic of the research. At this point the only agent that can be
invoked is the `literatureAgent`, because it is the only one that has
all its required inputs, in this case the `topic`, present in the
`AgenticScope`. The invocation of this agent produces the
`researchFindings` variable, which is added to the `AgenticScope` state,
and this new variable triggers the invocation of the `HypothesisAgent`.
Then this produces a `hypothesis` that in turn triggers the
`criticAgent`. Finally, the `ValidationAgent` takes in input both the
`hypothesis` and the `critique` and generates a new `hypothesis` that
eventually retriggers the other agents again. In the meanwhile the
`ScorerAgent` gives a `score` to the `hypothesis` and the process
terminates when this `score` is greater than or equal to 0.85, or when a
maximum of 10 agents invocations have been performed. The following
image summarizes all the agents and variables involved in this
execution.

<img width="1693" height="1101" alt="p2p"
src="https://github.com/user-attachments/assets/38d96c6d-c4b8-49ac-ae5f-6741067a2ab7"
/>


For instance a typical run of this example could terminate because the
`ScorerAgent` produced a score above the predetermined threshold

```
Current hypothesis score: 0.95
```

and the final output could be something like:

```
Based on the provided references, here are some key points about stochastic gravitational wave backgrounds (SGWBs) from primordial black holes (PBHs):

1. **Detection Rates and Sources:**
   - The detection rate of gravity waves emitted during parabolic encounters of stellar black holes in globular clusters was estimated by Kocsis et al. [85].
   - Gravitational wave bursts from PBH hyperbolic encounters were discussed by García-Bellido and Nesseris [93].

2. **Energy Emission:**
   - The energy spectrum of gravitational waves from hyperbolic encounters was studied by De Vittori, Jetzer, and Klein [88].
   - Gravitational wave energy emission and detection rates for PBH hyperbolic encounters were analyzed by García-Bellido and Nesseris [90].

3. **Template Banks:**
   - Template banks for gravitational waveforms from coalescing binary black holes (including non-spinning binaries) were developed by Ajith et al. [92].

4. **Constraints on PBHs:**
   - Constraints on primordial black holes were reviewed by Carr, Kohri, Sendouda, and Yokoyama [98].
   - Universal gravitational wave signatures of cosmological solitons were discussed by Lozanov, Sasaki, and Takhistov [100].

5. **Induced SGWBs:**
   - Doubly peaked induced stochastic gravitational wave backgrounds were tested for baryogenesis from primordial black holes by Bhaumik et al. [101].
   - Distinct signatures of spinning PBH domination and evaporation, including doubly peaked gravitational waves, dark relics, and CMB complementarity, were explored by Bhaumik et al. [101].

6. **Future Detectors:**
   - Future detectors like Taiji, LISA, DECIGO, Big Bang Observer, Cosmic Explorer, Einstein Telescope, and KAGRA are expected to contribute significantly to the detection of SGWBs from PBHs.

7. **Pulsar Timing Arrays:**
   - Pulsar timing arrays have been used to search for an isotropic stochastic gravitational wave background [73-75].

8. **Template Banks and Simulations:**
   - Template banks like those developed by Ajith et al. are crucial for matching observed signals with theoretical predictions.
```
2025-11-11 16:18:41 +01:00