{"id":50878385,"url":"https://github.com/Ugbot/Agentic-Streaming","last_synced_at":"2026-07-03T02:01:17.221Z","repository":{"id":319682935,"uuid":"1076618112","full_name":"Ugbot/Agentic-Streaming","owner":"Ugbot","description":null,"archived":false,"fork":false,"pushed_at":"2026-06-14T17:41:14.000Z","size":2150,"stargazers_count":32,"open_issues_count":0,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-14T18:04:42.975Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Ugbot.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-10-15T05:47:11.000Z","updated_at":"2026-06-14T17:41:04.000Z","dependencies_parsed_at":null,"dependency_job_id":"cfaf74ee-2aec-4573-b68a-263aca742db5","html_url":"https://github.com/Ugbot/Agentic-Streaming","commit_stats":null,"previous_names":["ugbot/agentic-flink"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Ugbot/Agentic-Streaming","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ugbot%2FAgentic-Streaming","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ugbot%2FAgentic-Streaming/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ugbot%2FAgentic-Streaming/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ugbot%2FAgentic-Streaming/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Ugbot","download_url":"https://codeload.github.com/Ugbot/Agentic-Streaming/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ugbot%2FAgentic-Streaming/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35069183,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-03T02:00:05.635Z","response_time":110,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-15T12:00:25.793Z","updated_at":"2026-07-03T02:01:17.213Z","avatar_url":"https://github.com/Ugbot.png","language":"Java","funding_links":[],"categories":["人工智能"],"sub_categories":["代理框架"],"readme":"\u003cdiv align=\"center\"\u003e\n\n# Agentic Streaming\n\n**Build resilient pipelines of stateful agents that act on continuous streams of data —\nchain them with almost any function call, reach almost any data system, and deploy the\nsame agent on Flink or a dozen other engines.**\n\n[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)\n[![Languages](https://img.shields.io/badge/languages-Python%20·%20JVM%20·%20Go%20·%20Clojure-informational.svg)](#whats-in-the-box)\n[![Backends](https://img.shields.io/badge/backends-Flink%20%2B%2012%20engines-success.svg)](docs/portability/parity-matrix.md)\n[![Build once](https://img.shields.io/badge/build%20once-deploy%20anywhere-orange.svg)](docs/portability/pipelines.md)\n\n[Why](#why) ·\n[What you can build](#what-you-can-build) ·\n[Quick start](#quick-start) ·\n[Deploy anywhere](#deploy-anywhere) ·\n[Architecture](#architecture) ·\n[Docs](#reference)\n\n\u003csub\u003eFormerly **Agentic Flink**. It began as an agent framework *for* Apache Flink and outgrew the name —\nthe same essence now runs across Python, the JVM, Go, and Clojure. Flink is still the first-class, most\nfeature-complete runtime; it's just no longer the only one.\u003c/sub\u003e\n\n\u003c/div\u003e\n\n---\n\n## Why\n\n**An agent is only worth building if it actually works — and \"works\" means it stays\nreliable under pressure.** The moment agents do real work — moving money, resolving\ntickets, touching infrastructure, answering customers — a clever demo isn't enough. It has\nto keep its promises when traffic spikes, a node dies, or a message is replayed.\n\nReliability at scale isn't a feature you bolt on later; it's the **substrate**. So instead\nof inventing a fragile new runtime, Agentic Streaming puts agents on the foundations that\nalready run the world's high-throughput, fault-tolerant systems — **durable keyed state,\nexactly-once / idempotent processing, backpressure, and automatic recovery**. The agent you\nprototype in a notebook is the *same* agent that survives production load, partial\nfailures, and restarts.\n\nThe worst outcome is building something awesome that falls over the first time it matters.\nThis project exists so you can build something awesome **and** keep it standing under\npressure — then deploy it on whichever battle-tested engine your scale demands.\n\n---\n\n## What you can build\n\nAgentic Streaming is for **resilient pipelines of stateful agents over continuous data** —\nnot one-shot chatbot calls.\n\n| You can… | How |\n|----------|-----|\n| 🌊 **Run agents over live event streams** | Kafka · Postgres CDC · Redis pub/sub · webhooks · NATS · Fluss · ZeroMQ · seeds — every input is a `Channel\u003cT\u003e`, and many fan into one agent |\n| 🧭 **Route \u0026 chain with deterministic outcomes** | a `router → path → verifier` graph dispatches each turn and **validates the reply**, with input/output **guardrails** and fully reproducible rule brains (no model required) |\n| 🛠️ **Call almost any function as a tool** | `@Tool` methods · async `ToolExecutor`s · **MCP** servers (stdio + HTTP/SSE) · DJL models (classifier/scorer/guardrail) · HTTP — one `ToolRegistry` |\n| 🤝 **Chain agents that call other agents** | **A2A** — a peer agent is just a tool: in-process, over a gateway (JSON-RPC / SSE / gRPC / REST), or as an explicit step, with retries + circuit-breaking |\n| 💾 **Keep state \u0026 survive failure** | first-class per-conversation memory + keyed state; durability from the engine — Flink checkpoints, Kafka Streams transactions, Pulsar/BookKeeper, Pekko persistence, Temporal history |\n| ✅ **Exactly-once where the engine gives it** | Flink checkpointed state · Kafka Streams `exactly_once_v2`; **idempotent / effectively-once** everywhere else (the `ConversationStore` is the source of truth) |\n| 🔄 **Resolve long work with the saga pattern** | compensation/rollback handlers unwind a multi-step flow when a later step fails; Temporal/Pekko add durable, retried, human-in-the-loop workflows |\n| ⏱️ **Detect patterns across events (CEP)** | a declarative [`cep:`](docs/portability/stream-stateful-core.md) block — \"3 anomalies on one host within 5 min → escalate\" — fires a tool or a derived event; **portable on every core** ([`incident.yaml`](examples/pipelines/incident.yaml)) and **native on Flink**, with timers · windows · replay · suspend/resume alongside |\n| 🔌 **Reach almost any data system** | memory, vectors, and long-term storage are SPIs — Postgres · Redis/Valkey · Fluss · pgvector/Qdrant · NATS KV — chosen by a connection link and **hot-swappable** without touching agent code |\n| 📦 **Build once, deploy anywhere** | define the whole agent in a [`pipeline.yaml`](docs/portability/pipelines.md) and run the *same* spec on Flink, Pekko, Clojure, or a dozen other backends (Python / JVM / Go / Clojure) |\n\n\u003e **The through-line:** resilient pipelines of agents that act on almost any data, chain\n\u003e with almost any function call, and reach almost any data system — with the correctness\n\u003e guarantees the underlying engine can give.\n\n---\n\n## Quick start\n\n**The same banking agent, on whichever runtime you like.** One\n[`pipeline.yaml`](examples/pipelines/banking.yaml) — a router→path→verifier graph with a tool, a\nknowledge base, and a guardrail — runs unchanged everywhere. Pick a runtime:\n\n```bash\ngit clone https://github.com/Ugbot/Agentic-Streaming.git \u0026\u0026 cd Agentic-Streaming\n```\n\n```bash\n# ⚡ Fastest — Python, model-free, no infra (30 seconds). Swap the backend without touching the spec:\npython -m agentic_pipeline run examples/pipelines/banking.yaml --text \"what is my balance?\"\npython -m agentic_pipeline run examples/pipelines/banking.yaml --backend nats --text \"card types?\"\n\n# 🎭 Agentic Pekko — the spec on an event-sourced actor runtime\nmvn -q -f ports/jagentic-core/pom.xml install -DskipTests\nmvn -f agentic-pekko/pom.xml exec:java -Dexec.mainClass=org.jagentic.pekko.PipelineMain \\\n  -Dexec.args=\"examples/pipelines/banking.yaml --text 'what is my balance?'\"\n\n# 🟢 Agentic Clojure — pure Clojure on Datomic\ncd agentic-clj \u0026\u0026 clojure -M:run \u0026\u0026 cd ..\n\n# 🌊 Apache Flink — the code-first framework (richest runtime)\ndocker compose up -d \u0026\u0026 docker compose exec ollama ollama pull qwen2.5:3b   # optional infra (or `podman compose`)\nmvn clean test\nmvn exec:java -Dexec.mainClass=\"org.agentic.flink.example.QuickStartExample\"\n# …or run the SAME pipeline.yaml as a real Flink job (source → native CEP → keyBy → agent → sink):\nmvn exec:java -Dexec.mainClass=\"org.agentic.flink.pipeline.FlinkPipelineRunner\" \\\n  -Dexec.args=\"examples/pipelines/banking.yaml --text 'what is my balance?'\"\n```\n\nEvery one answers with path `payments` and a balance of `1234.56`. The full walkthrough — including\nGo and the dozen swappable backends — is **[the banking agent on every runtime](docs/examples/banking-everywhere.md)**.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eBuild an agent — Flink Java DSL\u003c/b\u003e\u003c/summary\u003e\n\n```java\nAgent agent = Agent.builder()\n    .withId(\"research-bot\")\n    .withSystemPrompt(\"You are a research assistant.\")\n    .withChatConnection(LangChain4jChatConnection.ollama(\"http://localhost:11434\"))\n    .withChatSetup(ChatSetup.builder()\n        .withModel(\"qwen2.5:7b\")\n        .withTemperature(0.3)\n        .withMaxResponseTokens(2048)\n        .withOutputSchema(OutputSchema.of(ResearchVerdict.class))\n        .build())\n    .withShortTermTtl(Duration.ofMinutes(30))\n    .withVectorMemory(FlinkStateHnswVectorMemory.spec(768))\n    .withLongTermStore(StorageFactory.createLongTermStore(\"postgres\", pgConfig))\n    .withMemoryChannel(new KafkaContextChannel(\"kafka:9092\", \"agent-memories\", \"research-bot\"))\n    .withMcpServer(McpServerSpec.stdio(\"calc\", \"npx\", \"-y\", \"mcp-server-calculator\"))\n    .withSkill(Skill.builder()\n        .withName(\"citations\")\n        .withTools(\"doc-fetch\", \"summarize\")\n        .withSystemPromptFragment(\"Prefer primary sources. Cite arxiv IDs.\")\n        .build())\n    .withListener(new LoggingAgentEventListener(), new MetricsAgentEventListener())\n    .withMaxIterations(10)\n    .build();\n```\n\nEvery `with*` method is optional — defaults are discovered via `ServiceLoader`. The\nminimum viable agent is `Agent.builder().withId(...).withSystemPrompt(...).build()`.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eBuild an agent — Python\u003c/b\u003e\u003c/summary\u003e\n\nThe framework ships an [`agentic-flink` Python package](docs/python.md) with two paths:\n**PyFlink-native** (real Flink operators via PEMJA, see\n[`docs/pyflink-integration.md`](docs/pyflink-integration.md)) and **JPype standalone**\n(in-process JVM for notebooks/scripts).\n\n```python\nimport agentic_flink as af\nfrom agentic_flink import Agent, ChatSetup, langchain4j_ollama, tool\n\naf.start_jvm()\n\n@tool\ndef add(a: int, b: int) -\u003e int:\n    \"\"\"Add two numbers.\"\"\"\n    return a + b\n\nagent = (\n    Agent.builder()\n        .with_id(\"calc-bot\")\n        .with_system_prompt(\"You are a calculator.\")\n        .with_chat_connection(langchain4j_ollama())\n        .with_chat_setup(ChatSetup(model=\"qwen2.5:3b\"))\n        .with_tools(add)\n        .build()\n)\n```\n\nFull guide: [`docs/python.md`](docs/python.md) · examples under `python/agentic_flink/examples/`.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eBuild an agent — Agentic Pekko (actors)\u003c/b\u003e\u003c/summary\u003e\n\nThe agent brain is reused verbatim from the Flink-free core; only the actor + persistence shell is\nPekko (one event-sourced, sharded entity per conversation). Run any `pipeline.yaml` on it, or expose\nit over HTTP:\n\n```bash\n# HTTP front door (Agent Card + POST /agent) — A2A-interoperable\nmvn -f agentic-pekko/pom.xml exec:java -Dexec.mainClass=org.jagentic.pekko.http.HttpMain\ncurl -XPOST localhost:8080/agent -H 'content-type: application/json' \\\n  -d '{\"conversation_id\":\"c1\",\"user_id\":\"u\",\"text\":\"what is my balance?\"}'\n\n# durability showcase: passivate the entity, watch it rehydrate from the event journal\nmvn -f agentic-pekko/pom.xml exec:java -Dexec.mainClass=org.jagentic.pekko.RecoveryDemo\n```\n\nDurability profiles (memory · Postgres · Cassandra · Redis) are config-only. Full guide:\n[`agentic-pekko/README.md`](agentic-pekko/README.md).\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eBuild an agent — Agentic Clojure (Datomic)\u003c/b\u003e\u003c/summary\u003e\n\nA pure, idiomatic Clojure realization — brains/routers/verifiers are functions, the transcript is\nimmutable Datomic datoms (so history is time-travellable). Requires the\n[Clojure CLI](https://clojure.org/guides/install_clojure).\n\n```clojure\n;; brains are just functions; the graph is data\n(defn balance-brain [user-text ctx]\n  (str \"[payments] Your balance is \" (ctx/call-tool ctx \"get_balance\" {})))\n```\n\n```bash\ncd agentic-clj\nclojure -M:run            # banking demo (multi-turn, persisted state)\nclojure -M:http           # HTTP front door on :8080\nclojure -M:time-travel    # replay the transcript `as-of` an earlier point (Datomic immutability)\n```\n\nFull guide: [`agentic-clj/README.md`](agentic-clj/README.md).\n\n\u003c/details\u003e\n\n---\n\n## Deploy anywhere\n\nFlink is the first-class, feature-richest runtime — but the **agent itself is\nengine-agnostic**. Prototype on the embedded **Local** runtime, then move to a\nstreaming / durable / batch backend by changing one line of YAML.\n\n```yaml\n# pipeline.yaml — prompts, tools, calls-to-other-agents, retrieval, guardrails, stores\nbackend: nats            # local · celery · nats · faust · kafka-streams · pekko · temporal · …\nagent:\n  router:  { kind: keyword, default: general, rules: { payments: [balance], cards: [card] } }\n  paths:\n    payments: { brain: llm, prompt: \"You are a payments specialist.\", tools: [get_balance] }\n    cards:    { brain: rule, prompt: \"You answer card questions.\" }\n    general:  { brain: rule, prompt: \"You answer general questions.\" }\ntools:   [ { id: get_balance, kind: constant, value: 1234.56 } ]\nstores:  { conversation: { kind: redis, url: \"${AGENTIC_REDIS_URL}\" } }   # hot-swappable\n```\n\nExternal services (Redis/Valkey, Kafka/Fluss, Postgres, NATS) sit behind interfaces and\ncome up via [`examples/compose/externals.yml`](examples/compose/externals.yml).\n\n➡️ **[Pipeline reference](docs/portability/pipelines.md)** ·\n**[Parity matrix](docs/portability/parity-matrix.md)** (what each backend can do + its\nlimits) · **[Choosing a backend](docs/portability/choosing-a-backend.md)**\n\n---\n\n## The idea: an agent is a materialized view over a stream of events\n\n\u003e Treat an agent as **both stateful and a stream**. A conversation isn't a\n\u003e request/response call — it's an ordered **log of events** (turns, tool results, model\n\u003e outputs, routing decisions), and the agent's state is just a **materialized view** over\n\u003e that log: *the value you get by replaying its events.*\n\nTwo long-standing patterns fall straight out of that — and they're the real ethos here:\n\n- **Event sourcing** — the log is the source of truth, state is derived. That's the\n  durability / replay / audit / recovery story every engine implements differently (Flink\n  checkpoints, Kafka/NATS offsets, Pulsar BookKeeper, Pekko persistence, Temporal history).\n- **CQRS** — a **command** (\"process this turn\") is an ordered, single-writer-per-conversation\n  mutation; a **query** (\"what's the current answer/state?\") is a fan-outable read of the\n  view. Separating them lets a conversation be both a durable keyed entity *and* a stream.\n\nEvery engine here is, at heart, the same move: **materialize a series of events into a\nvalue, in order, durably, per key** — see the\n[capability inventory](docs/portability/00-essence-and-core-abstractions.md).\n\n---\n\n## What's in the box\n\n| Component | What it is | Start here |\n|-----------|-----------|------------|\n| **Flink framework** *(first-class)* | the full agent framework on Apache Flink — state-first memory, vector memory, CEP, chat/embedding/tool/inference SPIs, A2A, RAG, PyFlink | this README |\n| **Agentic Pekko** *(first-class)* | the agent essence on **Apache Pekko** actors — one event-sourced, cluster-sharded entity per conversation (single-writer + durable + recoverable), async turns, `backend: pekko`, Pekko HTTP + Kafka-Streams front doors, durability on memory/Postgres/Cassandra/Redis | [`agentic-pekko/`](agentic-pekko/) |\n| **Agentic Clojure** *(first-class)* | the agent essence as **pure, idiomatic Clojure** (no Java-core dep) on **Datomic** — each message an immutable datom, so the transcript *is* an event log with time-travel; functions for brains/routers/verifiers, the FNV embedder at byte-parity, EDN+YAML pipeline loader, http-kit + MCP-stdio front doors | [`agentic-clj/`](agentic-clj/) |\n| **Portability pack** | the same essence on **12 engines** across **3 pure cores** (`pyagentic` / `jagentic-core` / `goagentic`) + 2 HTTP gateways; a new tool/path in a core propagates to every port. The cores are **near-complete standalone agent frameworks** — real LLM/embedding libs, structured output, skills, MCP + A2A clients, saga, context-window mgmt, an in-process **HNSW** index, vector/long-term/conversation store SPIs (Qdrant/Postgres/Redis), web toolkit, DL-inference SPI | [`ports/`](ports/) |\n| **Declarative pipelines** | one `pipeline.yaml` (or EDN) → any backend; loaders in Python, JVM, Go, and Clojure | [`pipelines.md`](docs/portability/pipelines.md) |\n| **Tool services** | the toolkit (web scraping, **Tika**, RAG, inference, utilities) as standalone, framework-agnostic tools any LLM/framework runs over **MCP · REST · gRPC · Kafka/Redis** (Quarkus, Flink-free) | [`tool-services/`](tool-services/) · [`tool-services.md`](docs/portability/tool-services.md) |\n| **Design docs** | per-engine mapping, parity matrix, choosing-a-backend | [`docs/portability/`](docs/portability/) |\n\n---\n\n## Architecture\n\n\u003cdetails open\u003e\n\u003csummary\u003e\u003cb\u003eThe agent turn (every runtime)\u003c/b\u003e\u003c/summary\u003e\n\nOne turn is the same pipeline everywhere — the **essence** lives in a Flink-free core; each runtime\nonly supplies the seam that runs it (ordering + durability).\n\n```\n        Event in  (a Channel / HTTP / Kafka / queue / seed)\n                        |\n                        v\n        +-------------------------------+\n        |  input guardrails             |   regex · classifier — block / allow\n        +---------------+---------------+\n                        v\n        +-------------------------------+\n        |  router                       |   keyword / LLM → pick a path\n        +---------------+---------------+\n                        v\n        +-------------------------------+\n        |  path brain                   |   rule | ReAct LLM loop\n        |    · ToolRegistry (+ MCP)     |   call functions / peer agents (A2A)\n        |    · retrieval (hot + cold)   |   RAG over the embedder + vector store\n        |    · context-window (MoSCoW)  |\n        +---------------+---------------+\n                        v\n        +-------------------------------+\n        |  verifier                     |   validate the reply (e.g. prefix / schema)\n        +---------------+---------------+\n                        v\n        +-------------------------------+\n        |  output guardrails → listeners|   logging · metrics · custom hooks\n        +---------------+---------------+\n                        v\n        Reply out  +  one ordered append to the durable conversation log\n```\n\n**The runtime supplies ordering + durability** — the agent code is identical:\n\n| Runtime | single-writer ordering | durability of the log |\n|---------|------------------------|-----------------------|\n| **Flink** | keyBy / keyed operator | checkpoints + keyed state |\n| **Agentic Pekko** | actor mailbox + cluster sharding | event-sourced persistence |\n| **Agentic Clojure** | per-conversation serialize | Datomic immutable datoms (+ time-travel) |\n| **Kafka Streams / Pulsar** | partition / Key_Shared | changelog / BookKeeper |\n| **Temporal** | one workflow per id | event history |\n\nSee the [capability inventory](docs/portability/00-essence-and-core-abstractions.md) for the\nengine-agnostic core + the per-engine seam.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eFlink-runtime specifics\u003c/b\u003e\u003c/summary\u003e\n\nOn Flink the loop additionally offers **CEP pattern matching** (validation / escalation / saga\ncompensation), **Flink-state-first short-term memory** (`ValueState`/`MapState` + `StateTtlConfig`,\ndurable via checkpoints — no external HOT tier), and **in-JVM vector memory over Flink state**\n(`FlinkStateHnswVectorMemory`):\n\n```\n        Events (any Channel\u003cT\u003e: Kafka / Postgres / Redis / webhook / seed)\n                        |\n                        v\n        +-------------------------------+\n        |  Flink CEP pattern matching   |   validation · escalation · compensation\n        +---------------+---------------+\n                        v\n        +-------------------------------+\n        |  Agent loop                   |   ChatConnection (SPI) · ToolRegistry + MCP\n        |                               |   ReAct / workflow / custom\n        +---------------+---------------+\n                        v\n        +-------------------------------+\n        |  Context management            |   MoSCoW 5-phase compaction\n        |                               |   embedder-driven relevancy\n        +---------------+---------------+\n                        v\n        +-------------------------------+\n        |  Memory                        |   short-term: Flink keyed state (+TTL)\n        |                               |   vector: Flink MapState KNN\n        |                               |   long-term: Postgres (opt.)\n        +---------------+---------------+\n                        v\n        +-------------------------------+\n        |  Listeners (SPI)               |   logging · metrics · custom\n        +-------------------------------+\n```\n\nShort-term memory is Flink-state-first: checkpoints provide durability and TTL runs\nincrementally inside the state backend. Long-term storage is opt-in (conversation\nresumption across job lifetimes + fact archival).\n\n\u003c/details\u003e\n\n---\n\n## Reference\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eKey features — essence (every runtime)\u003c/b\u003e\u003c/summary\u003e\n\nThese are the portable agent features — identical on Flink, Pekko, Clojure, the three cores, and\nevery backend (enforced by cross-core parity tests):\n\n- **Routed graph** — `router → path → verifier` with input/output **guardrails** (regex + classifier) and reproducible **rule brains** (no model required).\n- **LLM brain** — a bounded **ReAct** loop over a `ChatClient` SPI (Ollama/OpenAI/stub), with structured output.\n- **Tools** — one `ToolRegistry`: functions, **MCP** servers (stdio + HTTP/SSE), and HTTP, shared by every brain.\n- **A2A** — a peer agent is just a tool (card + send + retries), in-process or over a gateway.\n- **Retrieval** — the FNV-1a hashing embedder (byte-identical across languages) + cosine + a two-tier hot/cold retriever; in-process **HNSW** cold tier.\n- **Skills** — bundle tools + a prompt fragment + required facts onto a path.\n- **Context-window** — MoSCoW compaction of the replayed transcript to a token budget.\n- **Saga / compensation** — reverse-order rollback of a multi-step flow.\n- **Listeners** — lifecycle hooks (logging / metrics / custom).\n- **Declarative pipeline** — the whole agent as one `pipeline.yaml` (EDN too, in Clojure).\n- **Stores behind SPIs** — conversation / keyed-state / long-term / vector, hot-swappable per runtime.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eKey features — Flink runtime\u003c/b\u003e\u003c/summary\u003e\n\n- **Flink-state-first memory** — short-term memory is `ValueState`/`MapState` with `StateTtlConfig`; checkpoints provide durability with no external HOT tier.\n- **In-JVM vector memory** over Flink state — brute-force KNN or HNSW (`FlinkStateHnswVectorMemory`); SPI escape hatch for external HNSW backends.\n- **Named, shareable corpora** — `Corpus` with three flavours (single-operator, broadcast, external) so ingest + retrieve share one index.\n- **Unified `Channel\u003cT\u003e` SPI** — Kafka, Postgres CDC, Redis pub/sub, webhook, static seeds, LLM-driven tool invocations; many channels union into one operator.\n- **Web toolkit** — Jsoup + crawler-commons + Apache Tika behind `WebFetchTool`, `CrawlerCore`, `DocumentExtractor`.\n- **Postgres-default long-term storage** — resumption + fact archive via `LongTermMemoryStore`; Redis optional.\n- **Chat-model SPI** — `ChatConnection` (transport) split from `ChatSetup` (per-agent model/temperature/structured output). LangChain4J is the default impl, not the API.\n- **Embedder SPI** — `EmbeddingConnection` / `EmbeddingSetup` / `EmbeddingClient`; default talks to local Ollama.\n- **MCP support** — `tools/mcp/` wraps Model Context Protocol servers (stdio + HTTP/SSE) as ordinary `ToolExecutor`s.\n- **Traditional DL models** — `inference/` SPI for classifiers, scorers, embedders, generic models (DJL: PyTorch/TensorFlow/ONNX/HuggingFace). Use as tools, guardrails, the scorer's backend, or standalone.\n- **Structured output** — `OutputSchema\u003cT\u003e` infers JSON Schema from Lombok POJOs and parses LLM responses via Jackson.\n- **ReAct agent** — `ReActProcessFunction` packages the Thought/Action/Observation loop, bounded by `getMaxIterations()`.\n- **Skills** — bundle tools + system-prompt fragment + required facts; `AgentBuilder.withSkill(...)`.\n- **Listeners** — `AgentEventListener` SPI (nine lifecycle hooks); `LoggingAgentEventListener` + `MetricsAgentEventListener` ship in-box.\n- **CEP-driven orchestration** — Flink CEP patterns drive validation, escalation, saga compensation.\n- **`@Tool` annotation discovery** — LangChain4J-annotated tools, MCP tools, and `ToolExecutor`s share one `ToolRegistry`.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eKey features — Pekko runtime\u003c/b\u003e\u003c/summary\u003e\n\n- **Event-sourced sharded entity** — one `EventSourcedBehavior` per conversation; the mailbox gives single-writer ordering, the journal gives durability + recovery, Cluster Sharding gives one live entity per id across the cluster.\n- **Async turns** — `graph.handle` runs off the actor thread (blocking dispatcher + `pipeToSelf`), stashing concurrent turns; one `TurnCommitted` event per turn, `turnId` dedupe for at-least-once ingress.\n- **Durability profiles** — config-only: in-memory · Postgres (`pekko-persistence-jdbc`) · Cassandra · Redis (write-through).\n- **Front doors** — Pekko HTTP (Agent Card + `POST /agent`) and a backpressured Pekko Streams Kafka flow.\n- **`backend: pekko`** — any `pipeline.yaml` runs on the actor runtime via the `BackendProvider` SPI (`PipelineMain`). See [`agentic-pekko/`](agentic-pekko/).\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eKey features — Clojure runtime\u003c/b\u003e\u003c/summary\u003e\n\n- **Pure, idiomatic Clojure** — no Java-core dependency; brains/routers/verifiers are functions, the registry is a map, a turn is a pure transform over a context map.\n- **Datomic storage** — each message is an immutable datom, so the transcript *is* an event log; **time-travel** (`as-of`) replays any past state. Same client API for in-process `com.datomic/local` · Datomic Pro · Cloud.\n- **EDN + YAML pipeline loader** — the shared schema, parsed natively; runs `banking`/`banking-llm`/`banking-rag`.\n- **Front doors** — http-kit (Agent Card + `POST /agent`) and a JSON-RPC MCP stdio server over the tool registry. See [`agentic-clj/`](agentic-clj/).\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003ePluggable surfaces (SPI summary)\u003c/b\u003e\u003c/summary\u003e\n\n| Concern | Interface | Default | Discovery |\n|---------|-----------|---------|-----------|\n| Short-term memory | `memory.ShortTermMemorySpec` | `FlinkStateShortTermMemory` | `ServiceLoader` + builder |\n| Vector memory | `memory.vector.VectorMemorySpec` | `FlinkStateVectorMemory` / `FlinkStateHnswVectorMemory` | Builder |\n| Corpus | `corpus.CorpusSpec` | `SingleOperatorCorpus` / `BroadcastCorpus` / `ExternalCorpus` | Builder |\n| Long-term store | `storage.LongTermMemoryStore` | `PostgresConversationStore` | `ServiceLoader` + factory |\n| External vector store | `storage.VectorStore` | `PgVectorStore` (opt-in) | `ServiceLoader` + factory |\n| Channel (continuous input) | `channel.Channel\u003cT\u003e` | `StaticSeed`, `Kafka`, `Webhook`, `KafkaContext`, `PostgresChange`, `RedisPubSub`, `ToolInvocation` | Programmatic |\n| Chat transport | `llm.ChatConnection` | `LangChain4jChatConnection` (Ollama) | `ServiceLoader` |\n| Embedding transport | `embedding.EmbeddingConnection` | `OllamaEmbeddingConnection` / `DjlEmbeddingConnection` | `ServiceLoader` |\n| MCP server | `tools.mcp.McpServerSpec` | none | Programmatic |\n| Inference model | `inference.InferenceConnection` | `DjlInferenceConnection` (opt-in) | `ServiceLoader` + builder |\n| Guardrail | `inference.Guardrail` | none | Programmatic |\n| Web fetch | `web.WebFetchTool` / `web.CrawlerCore` | Jsoup + crawler-commons + Tika (opt-in) | Programmatic |\n| Listener | `listener.AgentEventListener` | `LoggingAgentEventListener` | `ServiceLoader` |\n| Tool | `tools.ToolExecutor` | built-ins + `@Tool` | `ToolRegistry` |\n\nLangChain4J is the default chat backend, wrapped behind `ChatConnection`. Power users can\ndowncast to `LangChain4jChatClient` and call `getUnderlyingModel()` for the raw\n`dev.langchain4j.model.chat.ChatLanguageModel`.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eExamples\u003c/b\u003e\u003c/summary\u003e\n\n**Portable examples (run on any runtime).** One spec, identical behaviour everywhere — full\nwalkthrough in **[the banking agent on every runtime](docs/examples/banking-everywhere.md)**.\n\n| Spec | Demonstrates | Run (pick a runtime) |\n|------|--------------|----------------------|\n| [`banking.yaml`](examples/pipelines/banking.yaml) | router→path→verifier, a tool, a guardrail | `python -m agentic_pipeline run examples/pipelines/banking.yaml --text \"…\"` · `clojure -M:run` · Pekko `PipelineMain` |\n| [`banking-llm.yaml`](examples/pipelines/banking-llm.yaml) | a bounded **ReAct LLM brain** on a path | `… run examples/pipelines/banking-llm.yaml --text \"…\"` |\n| [`banking-rag.yaml`](examples/pipelines/banking-rag.yaml) | HNSW cold tier, skills, context-window, classifier guardrail | `… run examples/pipelines/banking-rag.yaml --text \"how do I dispute a charge?\"` |\n| [`multiagent.yaml`](examples/pipelines/multiagent.yaml) | A2A — a peer agent as a tool | `… run examples/pipelines/multiagent.yaml --text \"escalate this\"` |\n\n**Runtime-distinctive demos** — Pekko durability/recovery (`RecoveryDemo`) · Clojure Datomic\ntime-travel (`clojure -M:time-travel`).\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eAdvanced — Flink-runtime showcases\u003c/b\u003e\u003c/summary\u003e\n\nThese exercise **Flink-only** capabilities (CEP, side outputs, keyed-state vector memory, Kafka\nstreaming). Each has an inline `README.md`, a walkthrough under [`docs/examples/`](docs/examples/),\nand a wrapper script under [`examples-bin/`](examples-bin/).\n\n| Use case | Package | Flink-only capability | Run |\n|----------|---------|-----------------------|-----|\n| Customer-support triage | `example.triage` | guardrail + scorer over keyed state | `./examples-bin/run-support-triage.sh` |\n| Real-time content moderation | `example.moderation` | OutputTag **side outputs** | `./examples-bin/run-moderation.sh` |\n| RAG research assistant | `example.rag` | **Flink-state** keyed vector memory | `./examples-bin/run-rag.sh` |\n| Anomaly + incident agent | `example.incident` | **Flink CEP** pattern matching | `./examples-bin/run-incident.sh` |\n| Live research + RAG | `example.research` | crawler frontier as Flink operators | `./examples-bin/run-live-research.sh` |\n| Markets (bond / crypto) | `example.markets` | **Kafka + Flink** streaming | `./examples-bin/run-bond-market.sh` |\n| Quick start | `example.QuickStartExample` | minimal agent, one tool | `mvn -q exec:java -Dexec.mainClass=…QuickStartExample` |\n\n\u003c/details\u003e\n\nNeed a recipe rather than a full example? See [docs/cookbook.md](docs/cookbook.md).\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eDocumentation index\u003c/b\u003e\u003c/summary\u003e\n\n| Document | Description |\n|----------|-------------|\n| [docs/examples/banking-everywhere.md](docs/examples/banking-everywhere.md) | **The same banking agent on every runtime** — one spec, the run command per runtime |\n| [agentic-pekko/README.md](agentic-pekko/README.md) | **Agentic Pekko** *(first-class)* — event-sourced sharded actor runtime |\n| [agentic-clj/README.md](agentic-clj/README.md) | **Agentic Clojure** *(first-class)* — pure Clojure on Datomic |\n| [docs/portability/pekko.md](docs/portability/pekko.md) · [clojure.md](docs/portability/clojure.md) | Per-engine design notes for the two newest first-class runtimes |\n| [docs/portability/pipelines.md](docs/portability/pipelines.md) | Declarative `pipeline.yaml` schema + loaders (Python/JVM/Go) |\n| [docs/portability/parity-matrix.md](docs/portability/parity-matrix.md) | What each backend can do + limitations; three-core parity |\n| [docs/portability/choosing-a-backend.md](docs/portability/choosing-a-backend.md) | Decision guide across Flink + 12 engines |\n| [docs/portability/stream-stateful-core.md](docs/portability/stream-stateful-core.md) | The **stream-stateful core** — CEP · timers · windows · replay · suspend/resume · tracing, on every core |\n| [docs/concepts.md](docs/concepts.md) | Core concepts — agents, events, tools, memory, the routed graph |\n| [docs/configuration.md](docs/configuration.md) | Configuration reference (env vars, resolution order) |\n| [docs/a2a.md](docs/a2a.md) | Agent-to-Agent (A2A) protocol — peer-as-tool, gateway, bridges |\n| [docs/memory.md](docs/memory.md) | Flink-state-first memory model, vector memory, feeds |\n| [docs/inference.md](docs/inference.md) | DL models as tools, guardrails, scorers, embedders |\n| [docs/channels.md](docs/channels.md) | `Channel\u003cT\u003e` SPI: Kafka, Postgres CDC, Redis, webhook, tool transport |\n| [docs/corpus.md](docs/corpus.md) | `Corpus` abstraction + three flavours |\n| [docs/web-toolkit.md](docs/web-toolkit.md) | Jsoup + crawler-commons + Tika: robots-aware fetch + extract |\n| [docs/python.md](docs/python.md) | Python API — JPype standalone + pointer to PyFlink-native |\n| [docs/pyflink-integration.md](docs/pyflink-integration.md) | PyFlink-native: agent plan + CompileUtils + PEMJA |\n| [docs/cookbook.md](docs/cookbook.md) | Short recipes for common SPI combinations |\n| [docs/examples/](docs/examples/) | Long-form walkthroughs of the headline use cases |\n| [docs/getting-started.md](docs/getting-started.md) | Setup guide and first steps |\n| [docs/guides/context-management.md](docs/guides/context-management.md) | MoSCoW prioritization and compaction |\n| [docs/guides/storage-quickstart.md](docs/guides/storage-quickstart.md) | Storage backend setup |\n| [docs/guides/openai-setup.md](docs/guides/openai-setup.md) | Configuring OpenAI as the chat backend |\n| [docs/guides/flink-agents-integration.md](docs/guides/flink-agents-integration.md) | Optional Apache Flink Agents bridge |\n| [docs/reference/agent-framework.md](docs/reference/agent-framework.md) | Framework reference and agent patterns |\n| [docs/reference/storage-architecture.md](docs/reference/storage-architecture.md) | Storage design |\n| [docs/reference/troubleshooting.md](docs/reference/troubleshooting.md) | Common issues and fixes |\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eRelationship to Apache Flink Agents · In development\u003c/b\u003e\u003c/summary\u003e\n\n**Relationship to Apache Flink Agents.** Agentic Streaming predates upstream Apache Flink\nAgents and stays compatible in *vocabulary* without a hard dependency. User-facing SPI\nnames (`ChatConnection`, `ChatSetup`, `Skill`, `OutputSchema`, `MemorySet`) mirror\nupstream's, so a bridge stays thin. The optional `plugins/flintagents/` module (gated by\nthe `flink-agents` Maven profile) provides bidirectional adapters.\n\n**In development.**\n- Advanced CEP patterns for multi-agent coordination\n- JMH benchmark suite for chat / embedding / vector-memory hot paths\n- HNSW-backed `VectorMemorySpec` (JVector or Lucene) as a drop-in upgrade\n- Native PyFlink port of the memory primitives\n- Plugin refresh to upstream Flink Agents 0.3-SNAPSHOT\n\n\u003c/details\u003e\n\n---\n\n## Requirements\n\n- **Java 17+** · **Maven 3.8+** — the Flink framework (Apache Flink 2.2, native FLIP-27/143) **and** Agentic Pekko (built separately after `mvn -f ports/jagentic-core/pom.xml install`)\n- **Clojure CLI (tools.deps)** — only for Agentic Clojure under `agentic-clj/`\n- **Go 1.24+** — only for the Go core / gateway / engines under `ports/go/`\n- **Python 3.11+** — only for the pure-Python cores, ports, and the FastAPI gateway\n- **Docker or Podman** — only for optional Postgres / Redis / Ollama / NATS services\n- **Ollama** — for local LLM examples\n\n## Contributing\n\nContributions welcome — open an issue or PR. Especially valued: additional\n`ChatConnection`, `EmbeddingConnection`, `LongTermMemoryStore`, `VectorStore`,\n`InferenceConnection`, and `Channel\u003cT\u003e` implementations.\n\n## License\n\n[Apache License 2.0](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FUgbot%2FAgentic-Streaming","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FUgbot%2FAgentic-Streaming","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FUgbot%2FAgentic-Streaming/lists"}