From 24817e973716a3716e02d2dd9a7c873f6ea3d32a Mon Sep 17 00:00:00 2001 From: Shudipto Trafder Date: Fri, 30 Oct 2026 16:47:06 +0600 Subject: [PATCH] Update to 1.0.0rc2: Adjust versioning, enhance reasoning defaults, and improve error handling - Updated version numbers across documentation and code to 1.0.0rc2. - Changed reasoning defaults to each provider's lowest effort. - Enhanced OpenAI Responses API usage by default. - Introduced stricter ID validation and error handling for resume and write conflicts. - Added new Redis and media limits, along with shutdown settings. - Improved handling of stream and realtime edge cases in the client. - Documented breaking changes and upgrade notes for seamless transition. --- src/content/docs/concepts/agents-and-tools.md | 7 ++- src/content/docs/get-started/installation.md | 8 +-- src/content/docs/guides/configure-agent.md | 8 +-- src/content/docs/guides/graceful-shutdown.md | 2 +- src/content/docs/integrations/anthropic.md | 2 +- src/content/docs/integrations/google.md | 2 +- src/content/docs/integrations/models.md | 2 +- src/content/docs/integrations/openai.md | 17 ++++-- .../docs/integrations/postgres-and-redis.md | 1 + src/content/docs/project/index.md | 2 +- src/content/docs/project/upgrade-to-1.0.md | 31 +++++++++- src/content/docs/reference/error-codes.md | 2 +- src/content/docs/reference/python/agent.md | 8 +-- .../docs/reference/python/checkpointers.md | 3 +- .../docs/reference/python/memory-stores.md | 4 ++ src/content/docs/server/cli.md | 4 +- .../docs/server/production-checklist.md | 2 +- src/content/docs/testing/criteria.md | 2 +- src/content/releases/api-1.0.0rc2.md | 53 ++++++++++++++++ src/content/releases/client-1.0.0-rc.2.md | 46 ++++++++++++++ src/content/releases/core-1.0.0rc2.md | 60 +++++++++++++++++++ src/data/project-stats.json | 12 ++-- src/lib/site.ts | 2 +- src/pages/index.astro | 8 +-- 24 files changed, 244 insertions(+), 44 deletions(-) create mode 100644 src/content/releases/api-1.0.0rc2.md create mode 100644 src/content/releases/client-1.0.0-rc.2.md create mode 100644 src/content/releases/core-1.0.0rc2.md diff --git a/src/content/docs/concepts/agents-and-tools.md b/src/content/docs/concepts/agents-and-tools.md index eec61d2a..c70c002d 100644 --- a/src/content/docs/concepts/agents-and-tools.md +++ b/src/content/docs/concepts/agents-and-tools.md @@ -128,7 +128,10 @@ agent = Agent( # OFF reasoning_config=None -# On, medium effort (default for Google: thinking_budget=8192) +# On, lowest effort per provider (the default; Google thinking_budget=512) +reasoning_config=True + +# Medium effort (Google thinking_budget=8192) reasoning_config={"effort": "medium"} # High effort, Google @@ -141,7 +144,7 @@ reasoning_config={"thinking_budget": 5000} reasoning_config={"effort": "low", "summary": "auto"} ``` -Default is `{"effort": "medium"}`, so thinking is **on by default** for Google models. +Default is `True`: thinking is **on by default** at each provider's lowest effort (OpenAI `"minimal"`, Anthropic `"low"`, Google `"low"`). Pass a dict for more. --- diff --git a/src/content/docs/get-started/installation.md b/src/content/docs/get-started/installation.md index ea1f7277..dc8b7109 100644 --- a/src/content/docs/get-started/installation.md +++ b/src/content/docs/get-started/installation.md @@ -111,7 +111,7 @@ The `all` extra installs every other extra at once and is useful for local devel Version pinning still matters. From 1.0 the public API is stable under a deprecation policy: breaking changes arrive only in a major release, after at least one minor release of deprecation. The three packages share major.minor, and patch versions are independent. While 1.0 is a release candidate, install it with `--pre`: ```bash -pip install --pre "10xgraph==1.0.0rc1" "10xgraph-api==1.0.0rc1" +pip install --pre "10xgraph==1.0.0rc2" "10xgraph-api==1.0.0rc2" ``` Drop `--pre` once 1.0.0 is out. Read the [changelog](/changelog) before upgrading, and see the [upgrade guide](/docs/project/upgrade-to-1.0) if you come from 0.x. @@ -132,9 +132,9 @@ Example output (the exact formatting and versions vary by release): ```text $ 10xgraph version 10xgraph-api - Version: 1.0.0rc1 + Version: 1.0.0rc2 10xgraph (core) - Version: 1.0.0rc1 + Version: 1.0.0rc2 $ python -c "import tenxgraph; print(tenxgraph.__file__)" /path/to/.venv/lib/python3.12/site-packages/tenxgraph/__init__.py @@ -193,7 +193,7 @@ If you are building a JavaScript or TypeScript application that calls the 10xGra npm install 10xgraph-client@next ``` -The `next` tag points at the 1.0 release candidate (`1.0.0-rc.1`); use plain `npm install 10xgraph-client` once 1.0.0 is out. The main class is `TenxGraphClient`, and the package requires Node.js 18 or newer. See the [client documentation](/docs/client) for usage. +The `next` tag points at the 1.0 release candidate (`1.0.0-rc.2`); use plain `npm install 10xgraph-client` once 1.0.0 is out. The main class is `TenxGraphClient`, and the package requires Node.js 18 or newer. See the [client documentation](/docs/client) for usage. The client talks to a running 10xGraph API server (`10xgraph dev` locally) over HTTP, and you pass a thread ID to keep conversation history across runs. Use `10xgraph-api` 0.7.0 or newer with client 0.6.0 or newer: the client authenticates WebSockets with the `10xgraph-bearer` subprotocol, which older servers do not accept. HTTP calls work with either. See the [Quickstart](/docs/get-started/first-agent) for a complete example. diff --git a/src/content/docs/guides/configure-agent.md b/src/content/docs/guides/configure-agent.md index 22bda76e..5af76001 100644 --- a/src/content/docs/guides/configure-agent.md +++ b/src/content/docs/guides/configure-agent.md @@ -253,12 +253,12 @@ Multiple tags are supported; the agent can call any tool matching at least one t ## Reasoning configuration -10xGraph provides a unified `reasoning_config` across all providers that support reasoning. By default, reasoning is enabled at medium effort for models that support it (like OpenAI's o-series, Google's Gemini, and Anthropic's Claude). +10xGraph provides a unified `reasoning_config` across all providers that support reasoning. By default, reasoning is enabled at each provider's lowest effort for models that support it (OpenAI `"minimal"`, Anthropic `"low"`, Google `"low"`; pass a dict such as `{"effort": "medium"}` for more) (like OpenAI's o-series, Google's Gemini, and Anthropic's Claude). You can control reasoning mode with the `effort` key, which applies consistently across providers. Each provider translates this to its native settings. For providers without reasoning support, this parameter is safely ignored. ```python -# Default: medium effort (ON for reasoning models) +# Default: lowest effort per provider (ON for reasoning models) agent = Agent(model="gpt-4o") # High effort reasoning @@ -282,7 +282,7 @@ agent = Agent(model="claude-opus-5", reasoning_config={"effort": "high"}) | `effort` | OpenAI | Google `thinking_budget` | Anthropic | |---|---|---|---| | `"low"` | Low effort | 512 | Adaptive (conservative) | -| `"medium"` (default) | Medium effort | 8192 | Adaptive (balanced) | +| `"medium"` | Medium effort | 8192 | Adaptive (balanced) | | `"high"` | High effort | 24576 | Adaptive (thorough) | When you pass `effort`, Google's equivalent `thinking_budget` is computed automatically. The `summary` key (OpenAI-only) controls how extended thinking is summarized in the response. @@ -614,7 +614,7 @@ Agent( extra_messages: list[Message] | None = None, trim_context: bool = False, tools_tags: set[str] | None = None, - reasoning_config: dict | bool | None = {"effort": "medium"}, + reasoning_config: dict | bool | None = True, skills: SkillConfig | None = None, memory: MemoryConfig | None = None, retry_config: RetryConfig | bool | None = True, diff --git a/src/content/docs/guides/graceful-shutdown.md b/src/content/docs/guides/graceful-shutdown.md index a60775ca..869f8a0f 100644 --- a/src/content/docs/guides/graceful-shutdown.md +++ b/src/content/docs/guides/graceful-shutdown.md @@ -98,7 +98,7 @@ stats = await graph.aclose(grace=10, stop_timeout=5, timeout=5) 5. Background tasks (publisher events, memory writes) are drained for the rest of `timeout`, then cancelled. 6. The checkpointer, publisher and store are released, following the resource ownership rules (`compile(owns_resources=...)`). -Without arguments, the times split `compile(shutdown_timeout=...)` (default 30 seconds): 50% for `grace`, 25% for `stop_timeout`, 25% for `timeout`. The result is a stats dict with `runs` (`active`, `finished`, `stopped`, `cancelled`), `background_tasks` and one entry per released component. A second call returns `{"status": "already_closed"}`. `async with graph:` calls `aclose()` on exit. +Without arguments, the times split `compile(shutdown_timeout=...)` (default 30 seconds): 50% for `grace`, 25% for `stop_timeout`, 25% for `timeout`. The result is a stats dict with `runs` (`active`, `finished`, `stopped`, `cancelled`), `background_tasks`, `cleanup_tasks` (cancel saves and run-marker releases that outlived their run, waited for within the drain budget) and one entry per released component. A second call returns `{"status": "already_closed"}`. `async with graph:` calls `aclose()` on exit. ### Signals diff --git a/src/content/docs/integrations/anthropic.md b/src/content/docs/integrations/anthropic.md index 31346d48..1fdbe9cb 100644 --- a/src/content/docs/integrations/anthropic.md +++ b/src/content/docs/integrations/anthropic.md @@ -125,7 +125,7 @@ agent = Agent( ## Extended thinking and reasoning -Claude supports extended thinking (internal reasoning before responding) through the `reasoning_config` parameter. It is on by default with `{"effort": "medium"}`; pass `None` or `False` to turn it off: +Claude supports extended thinking (internal reasoning before responding) through the `reasoning_config` parameter. It is on by default at effort `"low"` (the lowest); pass a dict such as `{"effort": "medium"}` for more, or pass `None` or `False` to turn it off: ```python agent = Agent( diff --git a/src/content/docs/integrations/google.md b/src/content/docs/integrations/google.md index 0ead66ee..5f222715 100644 --- a/src/content/docs/integrations/google.md +++ b/src/content/docs/integrations/google.md @@ -260,7 +260,7 @@ config = EvalConfig( ## Thinking Models Gemini thinking models support extended thinking. Control it via `reasoning_config` -(the default is `{"effort": "medium"}`). Thinking is not applied when `output_schema` is set +(the default is effort `"low"`, which is `thinking_budget=512`; pass a dict for more). Thinking is not applied when `output_schema` is set or `output_type` is not text or json. ```python diff --git a/src/content/docs/integrations/models.md b/src/content/docs/integrations/models.md index e485760c..500257a0 100644 --- a/src/content/docs/integrations/models.md +++ b/src/content/docs/integrations/models.md @@ -218,7 +218,7 @@ Here `app` is your compiled graph. Some models include explicit reasoning or thinking capabilities: -`reasoning_config` is on by default with `{"effort": "medium"}`. Pass `None` or `False` to turn it off. +`reasoning_config` is on by default at each provider's lowest effort (OpenAI `"minimal"`, Anthropic `"low"`, Google `"low"`). Pass a dict such as `{"effort": "medium"}` for more, or pass `None` or `False` to turn it off. - **OpenAI:** `effort` is sent as `reasoning_effort` (Chat Completions) or `reasoning` (Responses API). - **Anthropic:** `effort` becomes `thinking={"type": "adaptive"}` plus `output_config={"effort": ...}`. diff --git a/src/content/docs/integrations/openai.md b/src/content/docs/integrations/openai.md index b8fce53b..b1a0f6ec 100644 --- a/src/content/docs/integrations/openai.md +++ b/src/content/docs/integrations/openai.md @@ -247,10 +247,10 @@ cache still fires automatically when the judge prompt prefix is stable (same rub ## Reasoning Models Reasoning models such as `o4-mini` are controlled via `reasoning_config`. The default is -`{"effort": "medium"}`. +effort `"minimal"` (the lowest); pass a dict for more. ```python -# Enable with defaults (effort="medium") +# Enable with defaults (effort="minimal") agent = Agent(model="o4-mini", reasoning_config=True) # Set effort level @@ -264,8 +264,12 @@ agent = Agent(model="o4-mini", reasoning_config=False) ``` On Chat Completions, `effort` is sent as `reasoning_effort`; on the Responses API the whole -dict is sent as `reasoning` (so `summary` is also allowed). Because the default is on, pass -`reasoning_config=None` when using a model that does not accept reasoning parameters. +dict is sent as `reasoning` (so `summary` is also allowed). When reasoning is on and you set no +`summary`, the Responses request asks for `summary: "auto"`. If the reasoning came from the default +and the model answers with a 400 that names the reasoning parameter (for example `gpt-4o`), the +call is retried once without it and the model is remembered for the process. An explicit +`reasoning_config` dict is never dropped and still raises, so pass `reasoning_config=None` for a +model that does not accept reasoning parameters. --- @@ -309,8 +313,9 @@ agent = Agent( When `base_url` is set and you do not pass `api_style`, the Agent uses Chat Completions, because most local servers only support it. If you pass `api_style="responses"` with a -`base_url`, the Agent tries the Responses API on the first call. If the server rejects it, -the Agent logs one warning and uses Chat Completions for the rest of its lifetime. +`base_url`, the Agent tries the Responses API on the first call. If the server answers 404, +405 or 501 (no Responses API), the Agent logs one warning and uses Chat Completions for the rest +of its lifetime. Other errors, such as a 429 or a timeout, are raised and do not switch it. Prompt caching params (`prompt_cache_key`, `prompt_cache_retention`) have no effect on local servers unless the server explicitly implements them. diff --git a/src/content/docs/integrations/postgres-and-redis.md b/src/content/docs/integrations/postgres-and-redis.md index 4061fcff..5aee160e 100644 --- a/src/content/docs/integrations/postgres-and-redis.md +++ b/src/content/docs/integrations/postgres-and-redis.md @@ -125,6 +125,7 @@ You must supply one Postgres source (`postgres_dsn` or `pg_pool`) and one Redis | `redis` | Redis client | `None` | Existing `redis.asyncio.Redis` instance | | `redis_pool` | `ConnectionPool` | `None` | Existing Redis connection pool | | `redis_pool_config` | `dict` | `None` | Extra keyword arguments for the Redis pool, merged over the defaults. The pool is capped at `max_connections=50`, and a caller past the cap waits up to `timeout=5.0` seconds for a free connection. Override either key. | +| `redis_breaker_cooldown` | `float` (kwarg) | `5.0` | Seconds to skip Redis after a connection failure. The checkpointer falls back to Postgres (or no cache) at once during the cool-down, so a Redis outage does not slow every run step. `0` disables it. | | `schema` | `str` | `"public"` | Postgres schema for the tables. Must match `^[a-zA-Z_][a-zA-Z0-9_]*$` | | `cache_ttl` | `int` (kwarg) | `86400` | Redis cache lifetime in seconds | | `state_history_limit` | `int` (kwarg) | `20` | State snapshots kept per thread; older ones are pruned on each durable write | diff --git a/src/content/docs/project/index.md b/src/content/docs/project/index.md index caa53942..0c272cb4 100644 --- a/src/content/docs/project/index.md +++ b/src/content/docs/project/index.md @@ -8,7 +8,7 @@ label: Overview updated: "2026-10-28" --- -This section covers 10xGraph as a project: who maintains it, how releases are announced, how to report a security problem, where to get help and how to contribute. It is MIT licensed, maintained by 10xScale, and at the 1.0 release candidate stage (1.0.0rc1, 2026-10-28) after its October 2026 rename from Agentflow. +This section covers 10xGraph as a project: who maintains it, how releases are announced, how to report a security problem, where to get help and how to contribute. It is MIT licensed, maintained by 10xScale, and at the 1.0 release candidate stage (1.0.0rc2, 2026-10-30) after its October 2026 rename from Agentflow. ## Start here diff --git a/src/content/docs/project/upgrade-to-1.0.md b/src/content/docs/project/upgrade-to-1.0.md index f38c14f2..ddbfdce2 100644 --- a/src/content/docs/project/upgrade-to-1.0.md +++ b/src/content/docs/project/upgrade-to-1.0.md @@ -24,7 +24,7 @@ read [Upgrade to 0.9](/docs/project/upgrade-to-0.9) first. client candidate is published under the `next` dist-tag. ```bash -pip install -U --pre "10xgraph==1.0.0rc1" "10xgraph-api==1.0.0rc1" +pip install -U --pre "10xgraph==1.0.0rc2" "10xgraph-api==1.0.0rc2" npm install 10xgraph-client@next ``` @@ -52,6 +52,17 @@ npm install 10xgraph-client@next only if you set `reasoning_config` yourself. With a `base_url` and `api_style="responses"`, a server that rejects the Responses API is probed once and the Agent then stays on Chat Completions. +- **Default reasoning is each provider's lowest effort.** `reasoning_config` left unset or set to + `True` used to mean `{"effort": "medium"}` (Google `thinking_budget=8192`). It now resolves per + request to OpenAI `"minimal"`, Anthropic `"low"` and Google `"low"` (`thinking_budget=512`); the + values are in `DEFAULT_REASONING_EFFORT_BY_PROVIDER`. Pass `{"effort": "medium"}` to keep the + old depth. `None` or `False` still turns reasoning off. +- **OpenAI Responses asks for a reasoning summary and retries models without reasoning.** With + reasoning on and no `summary` set, the request sends `summary: "auto"`. If the reasoning came + from the default and the model answers 400 naming the reasoning parameter (for example + `gpt-4o`), the call is retried once without it. An explicit `reasoning_config` dict is never + dropped. With a custom `base_url`, only 404, 405 and 501 switch the Agent to Chat Completions; + other errors are raised. - **The `openai` extra is `openai>=1.93.1,<4`.** openai 3.x uses httpx2, so an `http_client` passed through `llm_kwargs` must be an `httpx2.AsyncClient` there. @@ -92,6 +103,10 @@ npm install 10xgraph-client@next - **`aforget_memory` differs by store.** `QdrantStore` applies `memory_type`, `category` and `filters`. `Mem0Store` raises `ValueError` if any of them is passed. The `qdrant` extra needs `qdrant-client>=1.10.0` and a Qdrant server 1.10 or newer. +- **`GoogleEmbedding` sends Gemini task types.** `RETRIEVAL_DOCUMENT` when storing and + `RETRIEVAL_QUERY` when searching (`BaseEmbedding.aembed_query`, used by `QdrantStore.asearch`). + Set `document_task_type` and `query_task_type` to change them, or `None` to send none. Vectors + stored earlier stay searchable. ### Tools and handoffs @@ -154,6 +169,10 @@ npm install 10xgraph-client@next - **There are no default node or tool timeouts.** `node_timeout` and `tool_timeout` are off until you set them, and a value you set applies to both invoke and stream. Streaming runs also use the tool ledger now. +- **A failing eval judge is an error, not a 0.5 score.** The LLM judge and + `SimulationGoalsCriterion` now report an error with the real exception message when every + sample fails. Reports that relied on the 0.5 placeholder will show errors until the judge + model and key are fixed. `aclose()` stats also include `cleanup_tasks`. - **Realtime tool calls are deduplicated per thread.** A call replayed after a reconnect, or repeated by a new session on the same thread, returns the recorded result and does not run the tool again. The key is the thread id, a hash of the tool name and arguments, and the provider call id. This needs a checkpointer on the session. `GeminiLiveClient` also takes `connect_timeout` (default 30 s), so a connect that hangs fails after 30 seconds. See [Tool call deduplication](/docs/reference/python/realtime#tool-call-deduplication). - **New opt-in LLM limits, all off by default:** `stream_idle_timeout` (per agent, `set_default_stream_idle_timeout()` or `TENXGRAPH_LLM_STREAM_IDLE_TIMEOUT`; a stalled stream raises `LLMStreamIdleTimeoutError`) and the cross-process cap on `RetryConfig` (`distributed_max_concurrent_calls` and related fields; it fails open with a WARNING when Redis is down). See [Errors and limits](/docs/concepts/errors-and-limits). - **`LiveAgent.arun()` raises `RuntimeError` when the same instance already runs a session.** `arealtime()` runs each connection on its own copy (`LiveAgent.new_session()`). If you call `arun()` yourself, give each concurrent session its own `new_session()`. @@ -210,6 +229,10 @@ npm install 10xgraph-client@next - **The checkpointer's Redis pool is capped at 50 connections** and a caller past the cap waits up to 5 s for a free one, instead of opening a new connection. Raise `max_connections` or `timeout` through `redis_pool_config` if a busy worker needs more. +- **`PgCheckpointer` skips Redis for a cool-down after a connection failure.** The new kwarg + `redis_breaker_cooldown` (seconds, default `5.0`, `0` disables) makes it use its Postgres + fallback at once instead of waiting for the connect timeout on every Redis call. Checkpointers + also gain `aput_cache_value_if_absent`; a custom checkpointer inherits a get-then-put fallback. - **A thread stored at a node the graph no longer has fails with `StoredNodeMissingError`** (`GRAPH_NODE_MISSING_001`, API 409), naming the node and the thread. After renaming a node, add `compile(node_aliases={"old": "new"})`. Stored state written by a newer version raises @@ -235,6 +258,10 @@ npm install 10xgraph-client@next make their own ids (CopilotKit does by default) must set `"runs": {"thread_ids": "client"}`. The TypeScript client reads the live id into `session.threadId`, which is `string | null` until `session_started` arrives. +- **Writes during a run return 409.** `PUT` and `DELETE /v1/threads/{thread_id}/state`, + `POST /v1/threads/{thread_id}/messages`, `DELETE` of a thread message or a thread, and + `POST /v1/graph/fix` are refused at once while a run holds the thread. Retry after the run ends + or stop it first. - **Client dicts and lists have size caps:** 1000 keys per object, 10000 items per list and 200000 values in all, beside the 64-level depth cap. A larger body gets 422. The thread id rule now also covers the WebSocket `config.thread_id`, the live init frame and the AG-UI @@ -371,7 +398,7 @@ The extras raise these floors. A fresh install resolves them; an existing enviro After upgrading, before sending production traffic: -1. `10xgraph version` reports 1.0.0rc1 for core and the CLI. +1. `10xgraph version` reports 1.0.0rc2 for core and the CLI. 2. The server starts with `MODE=production` and explicit `ALLOWED_HOST` and `ORIGINS`. 3. A new conversation without a `thread_id` succeeds, and a client-invented id for a new thread gets 403 (unless you set `runs.thread_ids` to `"client"`). diff --git a/src/content/docs/reference/error-codes.md b/src/content/docs/reference/error-codes.md index d9196461..4976df89 100644 --- a/src/content/docs/reference/error-codes.md +++ b/src/content/docs/reference/error-codes.md @@ -349,7 +349,7 @@ The server maps exceptions to responses in `tenxgraph_api/src/app/core/exception A `429` is not a core exception either. The server returns it when the `rate_limit` window is used up (`error.code` `RATE_LIMIT_EXCEEDED`, with a `Retry-After` header) or when one user has more than `runs.max_concurrent_per_user` runs in flight (standard body, code `HTTPException`, no `Retry-After`). -In production the message of a 5xx response is replaced by a generic text and the real error goes to the server log. Messages of 4xx `HTTPException` errors are kept. Handled 4xx errors are logged at `WARNING` with no traceback, and 5xx errors at `ERROR` with the traceback, so alert rules for 4xx traffic must match `WARNING` (`10xgraph-api` 1.0.0rc1). A missing checkpointer answers `503` (`Checkpointer is not configured`), a thread state update with a bad `context` answers `422`, and a message id missing from a thread answers `404`. +In production the message of a 5xx response is replaced by a generic text and the real error goes to the server log. Messages of 4xx `HTTPException` errors are kept. Handled 4xx errors are logged at `WARNING` with no traceback, and 5xx errors at `ERROR` with the traceback, so alert rules for 4xx traffic must match `WARNING` (`10xgraph-api` 1.0.0rc2). A missing checkpointer answers `503` (`Checkpointer is not configured`), a thread state update with a bad `context` answers `422`, and a message id missing from a thread answers `404`. A `409` with the message `thread is busy` is not a core exception. The server returns it when another run is still active on the thread after 30 seconds. It uses the standard error body (`error.code` `HTTPException`), not the `state_conflict` shape. diff --git a/src/content/docs/reference/python/agent.md b/src/content/docs/reference/python/agent.md index e00a0d83..89996c76 100644 --- a/src/content/docs/reference/python/agent.md +++ b/src/content/docs/reference/python/agent.md @@ -35,7 +35,7 @@ def __init__( extra_messages: list[Message] | None = None, trim_context: bool = False, tools_tags: set[str] | None = None, - reasoning_config: dict[str, Any] | bool | None = {"effort": "medium"}, + reasoning_config: dict[str, Any] | bool | None = True, skills: SkillConfig | None = None, memory: MemoryConfig | None = None, retry_config: RetryConfig | bool | None = True, @@ -59,7 +59,7 @@ def __init__( | `trim_context` | `bool` | `False` | Trim conversation history to fit within the model's context window. | | `tools_tags` | `set[str] \| None` | `None` | Filter ToolNode tools by tag. Only tools with matching tags are offered to the LLM. | | `api_style` | `str` | `"responses"`, or `"chat"` when `base_url` is set | (via kwargs) OpenAI API style: `"chat"` (Chat Completions) or `"responses"` (Responses API). An explicit value always wins. With `"responses"` and a `base_url`, a server that rejects the Responses API is probed once, then the Agent uses Chat Completions for its lifetime. Any other value raises `ValueError`. | -| `reasoning_config` | `dict \| bool \| None` | `{"effort": "medium"}` | Reasoning config for models supporting extended thinking. `True` enables defaults, `False` or `None` disables, a dict sets model-specific options. See [Reasoning models](#reasoning-models). | +| `reasoning_config` | `dict \| bool \| None` | `True` | Reasoning config for models supporting extended thinking. `True` (or unset) turns reasoning on at each provider's lowest effort (OpenAI `"minimal"`, Anthropic `"low"`, Google `"low"`), `False` or `None` disables, a dict sets model-specific options. See [Reasoning models](#reasoning-models). | | `skills` | `SkillConfig \| None` | `None` | Agent Skills configuration per agentskills.io spec. Injects skill catalog and activation/read tools. See [`skills`](/docs/reference/python/skills). | | `memory` | `MemoryConfig \| None` | `None` | Long-term memory config for retrieving relevant context before each LLM call. See [Memory](#memory-augmented-agent). | | `retry_config` | `RetryConfig \| bool \| None` | `True` | Retry logic for transient API errors. `True` uses defaults; `False` or `None` disables; pass `RetryConfig` for tuning. See [Retry configuration](#retry-configuration). | @@ -217,7 +217,7 @@ agent = Agent( ## Reasoning models -Reasoning-capable models (for example OpenAI o-series and Gemini thinking models) are controlled with `reasoning_config`. Reasoning is on by default at medium effort: +Reasoning-capable models (for example OpenAI o-series and Gemini thinking models) are controlled with `reasoning_config`. Reasoning is on by default at each provider's lowest effort that still reasons (OpenAI `"minimal"`, Anthropic `"low"`, Google `"low"`, which is `thinking_budget=512`). The values are in `DEFAULT_REASONING_EFFORT_BY_PROVIDER` and are resolved per request, so a fallback model on another provider gets its own value. Pass a dict such as `{"effort": "medium"}` for more: ```python # Enable reasoning with default effort @@ -233,7 +233,7 @@ agent = Agent(model="o4-mini", reasoning_config={"effort": "high"}) agent = Agent(model="gemini-2.5-pro", reasoning_config={"thinking_budget": 8000}) ``` -`effort` applies to all providers, `summary` is OpenAI-only, and `thinking_budget` is Google-only and overrides `effort`. For Gemini, `effort` maps to a budget: `"low"` is 512 tokens, `"medium"` is 8192 (default), `"high"` is 24576. +`effort` applies to all providers, `summary` is OpenAI-only, and `thinking_budget` is Google-only and overrides `effort`. For Gemini, `effort` maps to a budget: `"low"` is 512 tokens, `"medium"` is 8192, `"high"` is 24576. --- diff --git a/src/content/docs/reference/python/checkpointers.md b/src/content/docs/reference/python/checkpointers.md index c9bee3da..c7e352fb 100644 --- a/src/content/docs/reference/python/checkpointers.md +++ b/src/content/docs/reference/python/checkpointers.md @@ -81,7 +81,7 @@ message = await checkpointer.aupdate_message_metadata( ) ``` -Optional, non-abstract async methods also exist on the base class, for example `aput_checkpoint`, `aput_cache_value`, `aget_cache_value`, `arequest_stop` and `aget_thread_owner`. Backends override them as needed. +Optional, non-abstract async methods also exist on the base class, for example `aput_checkpoint`, `aput_cache_value`, `aput_cache_value_if_absent` (set a cache value only if the key is missing: Redis `SET NX`, one SQLite statement, in-memory under its lock; the base class falls back to get-then-put), `aget_cache_value`, `arequest_stop` and `aget_thread_owner`. Backends override them as needed. ### Stop requests and active runs @@ -182,6 +182,7 @@ The constructor takes the connection arguments below as named parameters; the re | `redis_pool` | `ConnectionPool \| None` | `None` | Pre-created Redis connection pool. | | `redis_pool_config` | `dict \| None` | `None` | Config passed to the Redis pool if creating a new one. Merged over the defaults: a bounded `BlockingConnectionPool` with `max_connections=50` and `timeout=5.0` (seconds a caller waits for a free connection), plus Redis socket timeouts (5 s connect, 10 s read). Override any key. | | `schema` | `str` | `"public"` | PostgreSQL schema name where checkpointer tables live. Must match `^[a-zA-Z_][a-zA-Z0-9_]*$`, otherwise `ValueError`. | +| `redis_breaker_cooldown` (kwarg) | `float` | `5.0` | Seconds to skip Redis after a Redis connection failure. During the cool-down `PgCheckpointer` takes its usual fallback (Postgres, or no cache) at once instead of waiting for the connect timeout on every Redis call. `0` disables the circuit breaker. A cache entry whose invalidation was skipped is deleted when Redis is reachable again. | | `cache_ttl` (kwarg) | `int` | `86400` | Redis cache TTL in seconds (24 hours). | | `state_history_limit` (kwarg) | `int` | `20` | Number of historical state snapshots to retain per thread. | | `release_resources` (kwarg) | `bool` | `False` | On `arelease()`, close the Postgres and Redis resources even if you passed them in. By default only resources the checkpointer created itself are closed. | diff --git a/src/content/docs/reference/python/memory-stores.md b/src/content/docs/reference/python/memory-stores.md index b5b5d2af..bdf4a498 100644 --- a/src/content/docs/reference/python/memory-stores.md +++ b/src/content/docs/reference/python/memory-stores.md @@ -178,6 +178,10 @@ embedding = GoogleEmbedding( | `model` | `str` | `"gemini-embedding-001"` | Google embedding model to use. | | `api_key` | `str \| None` | None | Google API key. Reads from `GOOGLE_API_KEY` or `GEMINI_API_KEY` env vars if not provided. | | `output_dimensionality` | `int \| None` | None | Optional: reduce output dimension. Some models support this. | +| `document_task_type` | `str \| None` | `"RETRIEVAL_DOCUMENT"` | Gemini task type sent when embedding text to store. `None` sends none. | +| `query_task_type` | `str \| None` | `"RETRIEVAL_QUERY"` | Gemini task type sent when embedding a search query (`aembed_query`). `None` sends none. | + +`BaseEmbedding.aembed_query` embeds a search query and defaults to `aembed` for providers without a query task type; `QdrantStore.asearch` uses it. Vectors stored before task types were sent stay searchable. **Raises:** `ImportError` if `google-genai` is not installed. `ValueError` if no key is found. `dimension` returns `output_dimensionality` when set, `3072` for `gemini-embedding-001`, and `768` for other models. diff --git a/src/content/docs/server/cli.md b/src/content/docs/server/cli.md index 6d80fa00..b4444282 100644 --- a/src/content/docs/server/cli.md +++ b/src/content/docs/server/cli.md @@ -163,9 +163,9 @@ Output example: ``` 10xgraph-api - Version: 1.0.0rc1 + Version: 1.0.0rc2 10xgraph (core) - Version: 1.0.0rc1 + Version: 1.0.0rc2 ``` ### Preview animations diff --git a/src/content/docs/server/production-checklist.md b/src/content/docs/server/production-checklist.md index 8986ca72..6d58faa8 100644 --- a/src/content/docs/server/production-checklist.md +++ b/src/content/docs/server/production-checklist.md @@ -190,7 +190,7 @@ Expected tables in the `public` schema (or the `schema=` you pass): `threads`, ` ### Redis caching -Redis acts as a hot cache in front of Postgres. `PgCheckpointer` requires a Redis connection, but the durable data lives in Postgres. +Redis acts as a hot cache in front of Postgres. `PgCheckpointer` requires a Redis connection, but the durable data lives in Postgres. After a Redis connection failure, `PgCheckpointer` skips Redis for a short cool-down (`redis_breaker_cooldown`, 5 seconds by default, `0` disables it) and uses Postgres at once, so a Redis outage does not slow every run step. If several deployments share one Redis, set `REDIS_KEY_PREFIX` for the API (run locks, caps, ownership cache, token revocation) and `redis_key_prefix` on `PgCheckpointer` to the same value. They are two separate settings, and each prefixes only its own keys. diff --git a/src/content/docs/testing/criteria.md b/src/content/docs/testing/criteria.md index ff095958..49aabe02 100644 --- a/src/content/docs/testing/criteria.md +++ b/src/content/docs/testing/criteria.md @@ -144,7 +144,7 @@ config = EvalConfig( These criteria send the agent's response (and optionally the context) to a language model for scoring. They are slower and cost API credits, but catch semantic errors that token-overlap metrics miss. -The default judge model is `gemini-2.5-flash`. Override per criterion with `judge_model="gpt-4o"`. +The default judge model is `gemini-2.5-flash`. Override per criterion with `judge_model="gpt-4o"`. If the judge call fails (bad key, unsupported provider, empty or invalid JSON reply), the criterion reports an error with the real exception message instead of a 0.5 score. With several samples, a sample that succeeds still counts; the error is reported when every sample failed. `SimulationGoalsCriterion` behaves the same way. --- diff --git a/src/content/releases/api-1.0.0rc2.md b/src/content/releases/api-1.0.0rc2.md new file mode 100644 index 00000000..3ec707bc --- /dev/null +++ b/src/content/releases/api-1.0.0rc2.md @@ -0,0 +1,53 @@ +--- +package: api +version: "1.0.0rc2" +date: 2026-10-30 +summary: The second 1.0 release candidate. Stricter ids, resume and write conflicts as 409, a JWT algorithm allowlist, shutdown settings, Redis and media limits, and a run trace. Breaking changes included. +breaking: true +--- + +The second 1.0 release candidate. It is the `1.0.0rc1` code plus the changes below. Pip skips it unless you pass `--pre`: + +```bash +pip install -U --pre "10xgraph-api==1.0.0rc2" +``` + +It requires `10xgraph` 1.0.0rc2 and is aligned with `10xgraph-client` 1.0.0-rc.2. If you upgrade from 0.9.x, the rc1 breaking list applies to you as well. Read **Breaking** and the [upgrade guide](/docs/project/upgrade-to-1.0) before upgrading. + +### Breaking + +- **Ids in paths and bodies must match `^[A-Za-z0-9._:@-]{1,128}$`.** A `thread_id`, `message_id` or memory id that is longer or has other characters gets 422 (`VALIDATION_ERROR`). Snowflake integers and UUIDs fit. +- **Nested `initial_state`, `config` and `resume` values deeper than 64 levels get 422.** +- **Resume errors answer 409 or 422.** A wrong interrupt id, a resume sent to a thread that is not paused, and a new message sent to a thread paused at `interrupt()` return 409 (before the stream starts on `POST /v1/graph/stream`). A value that fails the interrupt's `response_schema` returns 422. +- **Writes during a run return 409.** State and message writes, thread and message deletes, and `POST /v1/graph/fix` are refused while a run holds the thread. **Migration:** retry after the run ends or stop it first. +- **`DELETE /v1/threads/{thread_id}` can return `success=false`** with `data.cleanup_failed` when file, trace or cache cleanup failed. The thread rows are deleted; retry the cleanup. +- **`JWT_ALGORITHM` must be on the allowlist** (`HS256`, `RS256`, `ES256`, `PS256`, `EdDSA` and their variants). `none` or any other value stops startup, as does `"auth": "jwt"` without PyJWT. The `auth` value must be exactly `"jwt"`. +- **The `graph:setup` scope is gone.** Remove it from your authorization config. +- **A run that hits its recursion limit answers 422 (`GRAPH_RECURSION_LIMIT`), not 500.** Graph validation errors use `VALIDATION_ERROR` only. +- **`POST /v1/graph/stream` is labelled `application/x-ndjson`** and idle streams send a blank keep-alive line every 15 s. **Migration:** update proxy rules or clients that matched `text/event-stream`. +- **AG-UI and `/v1/graph/live` follow `runs.thread_ids` like REST.** Frontends that make their own thread ids (CopilotKit does by default) must set `"runs": {"thread_ids": "client"}`. +- **`10xgraph build` refuses `--docker-compose` together with `--k8s`.** Run it once per target. +- **Uploads are checked against new limits:** images over 50,000,000 pixels and PDFs over 10 MB or 500 pages get 413. +- **`IS_DEBUG` is removed.** Debug follows `MODE`. The `/v1/evals/runs` endpoints are removed, and `10xgraph eval` writes only the JSON report. + +### Upgrade notes + +- Postgres: stop all old pods, run the schema migration with one new pod, then start the rest. `/health/ready` fails while the schema is behind. +- The generated Gunicorn command uses `TenxGraphUvicornWorker`: regenerate Docker and Kubernetes files with `10xgraph build`. Keep `--graceful-timeout` above the three `SHUTDOWN_*_SECONDS` settings. +- Handled client errors log one WARNING line, not an ERROR with a traceback. + +### Added + +- Shutdown settings `SHUTDOWN_GRACE_SECONDS`, `SHUTDOWN_STOP_SECONDS` and `SHUTDOWN_TIMEOUT_SECONDS`; 503 with `Retry-After` while closing; a final error chunk with `data.interrupted: true` on a cut stream; and a terminal `done` chunk on HTTP streams. +- Typed server errors with the request id, 429 `PROVIDER_RATE_LIMITED`, and `Retry-After` on 429 and 409. +- Redis settings `REDIS_SOCKET_TIMEOUT`, `REDIS_CONNECT_TIMEOUT`, `REDIS_POOL_TIMEOUT`, `REDIS_MAX_CONNECTIONS`, `REDIS_HEALTH_CHECK_INTERVAL` and `REDIS_KEY_PREFIX`. +- Media limits `MEDIA_MAX_FILES_PER_USER`, `MEDIA_MAX_USER_STORAGE_MB`, `MEDIA_MAX_IMAGE_PIXELS`, `MEDIA_MAX_PDF_MB`, `MEDIA_MAX_PDF_PAGES`, `MEDIA_INLINE_MAX_BYTES` and `MEDIA_SWEEP_INTERVAL_SECONDS`, and `GET /v1/files`. +- `has_more`, `offset` and `limit` on thread, message and memory lists. +- A run trace span tree on the observability route (dev only), and `realtime_options` in the graph details. +- `10xgraph revoke` for tokens (`--jti` or `--user`) with Redis-backed revocation. + +### Fixed + +- Stop and shutdown reach a REST stream after its first chunk, and a disconnected stream frees its thread only after the run is saved. +- `10xgraph eval` reports carry each case's expectations, and the `init` eval templates check what they declare and can pass. +- The template weather tool answers per city, and the default Gemini Live model name is current. diff --git a/src/content/releases/client-1.0.0-rc.2.md b/src/content/releases/client-1.0.0-rc.2.md new file mode 100644 index 00000000..5096a32a --- /dev/null +++ b/src/content/releases/client-1.0.0-rc.2.md @@ -0,0 +1,46 @@ +--- +package: client +version: "1.0.0-rc.2" +date: 2026-10-30 +summary: The second 1.0 release candidate, published under the next dist-tag. Drops Node.js 18, adds interrupt helpers, typed errors, abort signals and token functions, and fixes stream and realtime edge cases. +breaking: true +--- + +The second 1.0 release candidate, published to npm under the `next` dist-tag: + +```bash +npm install 10xgraph-client@next +``` + +`npm install 10xgraph-client` still installs 0.6.0 until 1.0.0 is released. Use this release with `10xgraph-api` 1.0.0rc2. New response fields are typed optional, so the client still works against older servers. See the [upgrade guide](/docs/project/upgrade-to-1.0). + +### Breaking + +- **Node.js 18 is no longer supported.** `engines` is `node >= 20.0.0`, and CI runs Node 20 and 22. **Migration:** run the client on Node.js 20 or later. +- **Typed change:** `RealtimeSession.threadId` is `string | null`. It is `null` until the `session_started` event arrives when you passed no `thread_id`. Handle `null` or wait for the event. + +### Behaviour changes + +- `stream()` and `wsStream()` throw (`StreamError`, `WebSocketError`) when a stream is cut or the server closes the socket mid-run. Before, they ended as if the run had succeeded. +- `timeout` is an idle timeout on `stream()` and `wsStream()`: it limits the wait on the network, not the whole run. +- Timeouts and network failures throw `RequestTimeoutError` and `NetworkError`. Check the class, not the message text. +- A `baseUrl` with a trailing slash is accepted. + +### Added + +- `Interrupt` type, `getInterrupt(chunk)`, `approveInterrupt()` and `rejectInterrupt()` to answer a paused run. +- `authToken` can be a function called on every request and realtime reconnect; `setAuthToken()` and `clearAuth()`. +- A `signal` option on every request method, not only `invoke()`, `stream()` and `wsStream()`. +- Error classes `RequestTimeoutError`, `NetworkError`, `WebSocketError`, `StreamError` and `RateLimitError` (with `retryAfterSeconds`). Errors carry `cause`, `endpoint`, `method` and `requestId`. +- `validate(args)` and `maxArgsBytes` on remote tool registrations; declared `parameters` are checked before the handler runs. +- `listMemories` takes `offset` and returns `has_more` and `next_offset`; `listFiles(params?)` for `GET /v1/files`; `has_more`, `offset` and `limit` on thread lists. +- Run trace types, `GraphInfo.realtime_options` and extended eval report types. +- Live sessions without a `thread_id` use the server-created id from the `session_started` event and send it back on reconnect. + +### Fixed + +- Leaving a `for await` loop over `stream()` early now cancels the request instead of leaving the connection open and the thread answering 409. +- `wsStream()` no longer hangs on an error chunk, and a truncated stream line throws `StreamError`. +- A 409 throws `ConflictError` against the real server, not a `TypeError`. +- `client.realtime()` no longer crashes Node with an unhandled rejection when the connection fails. +- `searchMemory()` omits unset `memory_type`, `category` and `score_threshold`, so a search without a type covers all memory types. diff --git a/src/content/releases/core-1.0.0rc2.md b/src/content/releases/core-1.0.0rc2.md new file mode 100644 index 00000000..f41cb3e8 --- /dev/null +++ b/src/content/releases/core-1.0.0rc2.md @@ -0,0 +1,60 @@ +--- +package: core +version: "1.0.0rc2" +date: 2026-10-30 +summary: The second 1.0 release candidate. Lowest-effort default reasoning, OpenAI Responses by default, no default tool or node timeouts, typed tool arguments, and fixes for handoffs, streaming, shutdown and eval. Breaking changes included. +breaking: true +--- + +The second 1.0 release candidate. It is the `1.0.0rc1` code plus the changes below. Pip skips it unless you pass `--pre`: + +```bash +pip install -U --pre "10xgraph==1.0.0rc2" +``` + +`10xgraph-api` 1.0.0rc2 and `10xgraph-client` 1.0.0-rc.2 ship alongside. If you upgrade from 0.10.x, the [rc1 breaking list](/docs/project/upgrade-to-1.0) applies to you as well. Read **Breaking** and the [upgrade guide](/docs/project/upgrade-to-1.0) before upgrading. + +### Breaking + +- **Default reasoning is each provider's lowest effort.** `reasoning_config` left unset or set to `True` used to mean `{"effort": "medium"}` (Google `thinking_budget=8192`). It now resolves per request to OpenAI `"minimal"`, Anthropic `"low"` and Google `"low"` (`thinking_budget=512`), from `DEFAULT_REASONING_EFFORT_BY_PROVIDER`. **Migration:** pass `{"effort": "medium"}` to keep the old depth. `None` or `False` still turns reasoning off. +- **OpenAI Responses requests a reasoning summary by default.** With reasoning on and no `summary` set, the request sends `summary: "auto"`. If the reasoning came from the default and the model answers 400 naming the reasoning parameter (for example gpt-4o), the call is retried once without it. An explicit `reasoning_config` dict is never dropped. +- **A custom `base_url` switches to Chat Completions only when Responses is missing.** Only 404, 405 and 501 switch it; other errors, such as a 429 or a timeout, are raised. +- **`Agent` uses the OpenAI Responses API by default.** `api_style` defaults to `"responses"` (it was `"chat"`), except when `base_url` is set and `api_style` is not passed. **Migration:** pass `api_style="chat"` to keep the old behaviour. The `openai` extra is now `openai>=1.93.1,<4`; on openai 3.x an `http_client` in `llm_kwargs` must be an `httpx2.AsyncClient`. +- **Tool and node timeouts are off by default.** `DEFAULT_TOOL_TIMEOUT_SECONDS` and `DEFAULT_NODE_TIMEOUT_SECONDS` are now `None` (they were 300 s and 900 s). **Migration:** set `tool_timeout` or `node_timeout` in the run config; a value you set now applies to both `invoke` and `stream`. +- **Tool arguments are checked against the types the tool declares.** A value that converts cleanly is converted; one that cannot (a list for an `int`) gets a failed tool result. +- **Published events are snapshots.** Each event is copied before it is queued, so Kafka, Redis, RabbitMQ and OTEL consumers see the values at the moment of the event. +- **`pass_user_info_to_mcp=True` sends the user info as request metadata** (`meta`, `{"user": {...}}`), not as a `user` tool argument. A server that read `user` from the arguments must read it from the meta. +- **`LiveAgent.arun()` raises `RuntimeError` when the instance already runs a session.** **Migration:** give each concurrent session its own `LiveAgent.new_session()`. +- **A stop request is saved as `StopRequestStatus.STOPPED`.** Code that checks for `STOP_REQUESTED` after a stop must also accept `STOPPED`. +- **Sync `invoke()`, `stream()`, `stop()` and sync checkpointer methods raise `RuntimeError` inside a running event loop.** **Migration:** call `ainvoke`, `astream`, `astop` or `aget_state`. +- **`Message.reasoning` is removed.** **Migration:** read the `ReasoningBlock`s (`type == "reasoning"`) in `Message.content`. The Postgres `messages.reasoning` column is dropped (schema version 5): stop old pods, migrate, then start new ones. +- **`mem0ai` is bounded to `>=2.0,<3`.** Other extras raise their floors: `Pillow>=13.0.0`, `mcp>=1.30.0`, `opentelemetry-api` and `opentelemetry-sdk` `>=1.45.1`. + +### Added + +- `await graph.aclose(grace, stop_timeout, timeout)`: graceful shutdown in phases, with `GraphClosedError` for new runs, the opt-in `install_shutdown_signals`, and `compile(owns_resources=...)`. +- User simulator progress events through `on_event` on `UserSimulator.run` and `BatchSimulator.run_batch`. +- `ToolNode` options `max_result_chars`, `mcp_include`, `mcp_exclude`, `mcp_prefix`, `mcp_max_result_chars`, `mcp_max_description_chars` and `mcp_connect_timeout`, plus `refresh_mcp_tools()`. MCP tool lists are cached per `ToolNode`. +- `create_fetch_url`, `create_google_web_search` and `create_vertex_ai_search`: tool factories that fix hosts, model or datastore in code. +- `RetryConfig.jitter`, `max_concurrent_calls` and the opt-in cross-process cap `distributed_max_concurrent_calls`. +- `PgCheckpointer` `redis_key_prefix`, safe default timeouts, `aclear_state_cache`, and `aput_cache_value_if_absent` on the checkpointers. +- `compile(node_aliases=...)`, `StoredNodeMissingError`, `StateFormatVersionError`, `NothingToResumeError` and `InterruptPendingError`. +- `GoogleEmbedding(document_task_type=..., query_task_type=...)` and `BaseEmbedding.aembed_query`. +- A redesigned self-contained HTML eval report (scorecard). + +### Changed + +- `PgCheckpointer` skips Redis for a cool-down after a connection failure: new kwarg `redis_breaker_cooldown` (seconds, default 5.0, 0 disables). +- `GoogleEmbedding` sends `RETRIEVAL_DOCUMENT` when storing and `RETRIEVAL_QUERY` when searching; set the task types to `None` to send none. +- Large `data["state"]` in published events is replaced by a summary above `state_snapshot_limit` (default 65536). +- Realtime tool calls run once per thread, and a cancelled, crashed or shut-down run leaves a usable thread. +- Anthropic thinking blocks are stored with their signature and replayed unchanged. + +### Fixed + +- Multi-agent handoffs no longer leave an unanswered tool call: `SwarmAgent` gets a `_HANDOFF` node, and the handoff result tells the receiving agent it is in charge. +- Streaming: each item gets its own chunk, so clients see the deltas instead of the final message repeated. +- `PlanActReflectAgent` shows the planner's reply, not the reflector's review (reflector messages carry `metadata["internal"] = True`). +- Cancel and shutdown edge cases: `aclose()` waits for late cancel saves and run-marker releases (reported as `cleanup_tasks`), and a late save cannot overwrite the final one. +- Eval: a failing LLM judge reports an error with the real message instead of a 0.5 score. +- A Redis outage no longer slows every run step. diff --git a/src/data/project-stats.json b/src/data/project-stats.json index d2329b59..f077dbf0 100644 --- a/src/data/project-stats.json +++ b/src/data/project-stats.json @@ -14,20 +14,20 @@ "latest": [ { "package": "10xgraph", - "version": "1.0.0rc1", - "date": "2026-10-28", + "version": "1.0.0rc2", + "date": "2026-10-30", "label": "core" }, { "package": "10xgraph-api", - "version": "1.0.0rc1", - "date": "2026-10-28", + "version": "1.0.0rc2", + "date": "2026-10-30", "label": "API and CLI" }, { "package": "10xgraph-client", - "version": "1.0.0-rc.1", - "date": "2026-10-28", + "version": "1.0.0-rc.2", + "date": "2026-10-30", "label": "TS client" } ] diff --git a/src/lib/site.ts b/src/lib/site.ts index 0517be93..0fce47a8 100644 --- a/src/lib/site.ts +++ b/src/lib/site.ts @@ -14,7 +14,7 @@ export const SITE = { // Hosted playground (agentflow-playground/, Cloudflare). `10xgraph play` still opens the old // Firebase URL until the CLI's DEFAULT_PLAYGROUND_URL changes. playground: 'https://play.10xgraph.com', - version: '1.0.0rc1', + version: '1.0.0rc2', locale: 'en_US', org: { name: '10xScale', url: 'https://10xscale.ai' }, formerName: 'Agentflow', diff --git a/src/pages/index.astro b/src/pages/index.astro index 240e4f1b..d0f80874 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -24,7 +24,7 @@ const faq = [ }, { q: "Is the API server production-ready?", - a: "Yes. 10xScale runs its own AI products on it. Each part of running agents in production has its own options, and most of them are a key in 10xgraph.json or an environment variable. You tune production behavior without touching your agent code.\n\nSecurity: authentication is JWT or your own BaseAuth class. Authorization is owner-only threads, allow-all, or your own backend. MODE=production refuses to start with wildcard CORS plus credentials, rejects JWT secrets shorter than 32 bytes, and turns off the /docs pages by default. Security headers are on by default. The production template adds a prompt-injection validator and lifecycle validators that run before invoke, after each step and on error.\n\nReliability: tool calls are replay-safe after a crash, and versioned state writes stop two runs from overwriting each other. Node and tool timeouts stop a hung call from holding a worker. Thread state is cached in Redis and stored durably in PostgreSQL, so threads survive restarts.\n\nScale: rate limits use a sliding window keyed by IP, by user or globally, and they are stored in memory, in Redis so every worker shares them, or in your own backend. The server runs Gunicorn with Uvicorn workers, and you can run several instances behind a load balancer as long as they share PostgreSQL and Redis. WebSocket connection limits, upload size limits and allowed file types are configurable.\n\nDeployment and operations: 10xgraph build writes a Dockerfile, docker-compose.yml and a Kubernetes manifest. The manifest's grace period and probe timeouts let in-flight agent runs finish during a rolling deploy. 10xgraph audit checks the environment and config before you ship, and it exits with code 1 on failure, so it can gate CI. Every response carries an X-Request-ID, and you can send errors to Sentry, traces to OpenTelemetry, and runs to Logfire or LangSmith.\n\nThe core is at 1.0.0rc1, the 1.0 release candidate, so pin your versions and read the changelog when you upgrade." + a: "Yes. 10xScale runs its own AI products on it. Each part of running agents in production has its own options, and most of them are a key in 10xgraph.json or an environment variable. You tune production behavior without touching your agent code.\n\nSecurity: authentication is JWT or your own BaseAuth class. Authorization is owner-only threads, allow-all, or your own backend. MODE=production refuses to start with wildcard CORS plus credentials, rejects JWT secrets shorter than 32 bytes, and turns off the /docs pages by default. Security headers are on by default. The production template adds a prompt-injection validator and lifecycle validators that run before invoke, after each step and on error.\n\nReliability: tool calls are replay-safe after a crash, and versioned state writes stop two runs from overwriting each other. Node and tool timeouts stop a hung call from holding a worker. Thread state is cached in Redis and stored durably in PostgreSQL, so threads survive restarts.\n\nScale: rate limits use a sliding window keyed by IP, by user or globally, and they are stored in memory, in Redis so every worker shares them, or in your own backend. The server runs Gunicorn with Uvicorn workers, and you can run several instances behind a load balancer as long as they share PostgreSQL and Redis. WebSocket connection limits, upload size limits and allowed file types are configurable.\n\nDeployment and operations: 10xgraph build writes a Dockerfile, docker-compose.yml and a Kubernetes manifest. The manifest's grace period and probe timeouts let in-flight agent runs finish during a rolling deploy. 10xgraph audit checks the environment and config before you ship, and it exits with code 1 on failure, so it can gate CI. Every response carries an X-Request-ID, and you can send errors to Sentry, traces to OpenTelemetry, and runs to Logfire or LangSmith.\n\nThe core is at 1.0.0rc2, the 1.0 release candidate, so pin your versions and read the changelog when you upgrade." }, { q: "How does the server handle authentication and multi-user isolation?", @@ -80,7 +80,7 @@ const jsonLd = [ "description": "10xGraph is an open-source Python framework for production multi-agent AI. You write the agent, and 10xGraph generates the production server around it: authentication, scoped access control, owner-only threads, rate limits, and Docker and Kubernetes deployment. Memory has two tiers, with hot data in a Redis cache and cold data in PostgreSQL. MIT licensed, made by 10xScale.", "applicationCategory": "DeveloperApplication", "operatingSystem": "Linux, macOS, Windows", - "softwareVersion": "1.0.0rc1", + "softwareVersion": "1.0.0rc2", "programmingLanguage": "Python", "license": "https://opensource.org/licenses/MIT", "url": "https://10xgraph.com/", @@ -179,11 +179,11 @@ const jsonLd = [

What is 10xGraph?

10xGraph is an open-source Python framework for production multi-agent AI. You write the agent, and 10xGraph generates the production server around it: authentication, scoped access control, owner-only threads, rate limits, and Docker and Kubernetes deployment. Memory has two tiers, with hot data in a Redis cache and cold data in PostgreSQL. MIT licensed, made by 10xScale.

-

Updated October 2026 · v1.0.0rc1 · Read the concepts

+

Updated October 2026 · v1.0.0rc2 · Read the concepts

License
MIT, including the API server and CLI. Use it commercially, self-host it, fork it.
-
Runtime
Python 3.12+. Core 1.0.0rc1, API and CLI 1.0.0rc1, TypeScript client 1.0.0-rc.1.
+
Runtime
Python 3.12+. Core 1.0.0rc2, API and CLI 1.0.0rc2, TypeScript client 1.0.0-rc.2.
Memory
Hot: active thread state cached in Redis and read first. Cold: full history in PostgreSQL with versioned writes.
Dependencies
No LangChain. Dependency injection through InjectQ.