Netweb Enterprise Agent Engineering Framework
Project description
Netweb SDK
Enterprise-grade AI agent framework focused on building, running, and extending LLM-powered agents, tools, and memory stores — without any workflow or orchestration primitives.
Table of Contents
- Why Netweb SDK
- Installation
- Quick Start
- Core Concepts
- Agents
- Tools
- Memory
- Providers
- Streaming
- Tracing and Observability
- Retry and Fault Tolerance
- Examples
- Environment Variables
Why Netweb SDK
Netweb SDK provides a developer-friendly API to build LLM-driven assistants that integrate tools, memory, and provider adapters without forcing a graph/workflow abstraction. It is designed for use-cases where a single agent or a small collection of cooperating agents (coordinated by application code) is sufficient.
Key benefits:
- Structured tool calling and validation
- Pluggable memory backends (in-memory, vector stores, persistent stores)
- Provider-agnostic adapters (OpenAI, Anthropic, Google, local)
- Built-in tracing hooks for observability
Installation
pip install netweb-sdk
Required environment variables are documented at the end of this file.
Quick Start
import asyncio
from dotenv import load_dotenv
from sdk import create_agent, OpenAIProvider
load_dotenv()
agent = create_agent(
name="assistant",
llm=OpenAIProvider(model="gpt-4o-mini"),
memory=True,
)
async def main():
# use `nw_run` as the convenient blocking helper or `run` within async code
resp = await agent.nw_run("What is the capital of France?")
print(resp.output)
asyncio.run(main())
Core Concepts
- Agent — an LLM-powered unit with a role, goal, tools, and memory
- Tool — a Python function exposed to agents via structured JSON calling
- Provider — an LLM backend (OpenAI, Anthropic, Google, local)
Infrastructure features (memory, tracing, retries, streaming) are available without a workflow system.
Agents
Agents are created via create_agent(...). Typical configuration includes the following parameters: name, llm, tools, memory (bool or memory instance), input_schema, output_schema, prompt_path, system_prompt, retries, and retry_delay.
Example:
from sdk import create_agent, OpenAIProvider, get_tools
llm = OpenAIProvider(model="gpt-4o-mini")
agent = create_agent(
name="support_agent",
llm=llm,
tools=get_tools(["web_search"]),
memory=True,
system_prompt="You are a helpful support assistant.",
retries=2,
retry_delay=1.0,
)
async def main():
resp = await agent.nw_run("My invoice has wrong charges")
print(resp.output)
asyncio.run(main())
AgentResponse contains output, tool_calls, and metadata.
Notes on current behavior
- Memory role: assistant messages stored in memory use the agent's
namewhen available; if no name is provided the SDK falls back to the literal stringassistant. - Structured tool calling: when an LLM response includes a JSON object of the form {"tool": "<tool_name>", "args": {...}} the SDK will parse that JSON and attempt to execute the referenced tool using the exact parameter names from the tool schema. The executor removes surrounding Markdown code fences before parsing and supports both JSON and Python-literal dicts.
- Streaming + tool output: when streaming is used the LLM chunks are yielded as they arrive. After the stream completes the executor inspects the full output for a tool call — if a tool was invoked its result is returned as an additional chunk (prefixed with a newline).
Tools
Registerable via the @nw_tool decorator or available as built-ins. Tools expose a consistent schema, support sync/async execution, and are validated before execution.
Utilities:
nw_tool— decorator to register Python functions as toolsget_tools(names: list[str])— fetch tool instances by nameget_tool(name: str)— fetch a single toollist_tools()— list available tool metadata
Built-in examples: web_search, file_reader, file_writer, human_approval, escalation.
Custom tool example:
from sdk import nw_tool
@nw_tool("calculate_discount")
def calculate_discount(price: float, discount_percent: float) -> str:
final = price - (price * discount_percent / 100)
return f"Final price after {discount_percent}% discount is ${final:.2f}"
Memory
Memory options:
ConversationMemory— in-process conversation history (default whenmemory=True)PersistentMemory— durable store backed by Postgres/Redis (via checkpointers)
Example (in-memory):
agent = create_agent(..., memory=True)
await agent.nw_run("My name is Alice")
await agent.nw_run("What is my name?") # → "Your name is Alice."
Example (persistent):
from sdk import PersistentMemory
memory = await PersistentMemory.create(db_url=os.getenv("POSTGRES_URL"), thread_id="user_001")
agent = create_agent(..., memory=False)
agent.memory = memory
Providers
Adapters for multiple LLM backends; all support generate() and stream().
OpenAIProviderAnthropicProviderGoogleProviderOpenSourceProvider(HuggingFace, Ollama, local runtimes)
Example:
from sdk import OpenAIProvider
llm = OpenAIProvider(model="gpt-4o-mini", temperature=0.7)
Streaming
Agents and providers support streaming partial outputs. Use nw_run_streamed(...) to iterate chunks as they arrive.
async for chunk in agent.nw_run_streamed("Explain neural networks"):
print(chunk, end="", flush=True)
Tracing and Observability
Enable LangSmith-compatible tracing:
from sdk.tracing import enable_tracing, get_logger
enable_tracing(project_name="my-app")
logger = get_logger()
logger.info("Agent started")
Tracing captures LLM call spans, tool executions, and retry attempts.
LangSmith integration
- The SDK includes hooks for LangSmith-compatible tracing. When tracing is
enabled the executor records chain and LLM spans, and tool executions are
recorded with metadata (model, prompt/completion token estimates, streaming
flag, etc.). Set
LANGSMITH_API_KEYandLANGSMITH_PROJECTto enable it.
Retry and Fault Tolerance
Configure per-agent retry policy via retries and retry_delay. Retries are logged and surfaced in traces.
agent = create_agent(..., retries=3, retry_delay=1.0)
Behavioral notes
- The executor will retry transient operations (LLM generate and tool runs)
according to the agent's
retriesandretry_delaysettings. Errors are logged and surfaced in traces; unrecoverable exceptions are propagated to the caller.
Guardrails (Middleware)
This repository includes a small guardrails layer implemented as composable middleware to protect, observe, and modify requests/responses around LLM calls. The middleware lives under abstractions.guardrails.middleware and is also exported via the sdk.guardrails shim and top-level sdk package for convenience.
Available middleware
PIIRedactionMiddleware: redacts PII (emails, phone numbers, credit cards) from the input passed to the LLM. Whenredact_pii=Truethe middleware temporarily replacesctx.raw_inputwith a redacted version so downstream handlers receive a sanitized prompt. Optionally setredact_response=Trueto redact response text before it is logged or returned.RateLimitMiddleware: enforces per-minute and per-day request limits scoped by keys such asuser_id. Configureraise_on_exceedto either raise an exception or return a blockedAgentResponse.TokenBudgetMiddleware: estimates token usage (usestiktokenif available, falls back to a simple character heuristic) and enforces per-request and per-user daily budgets.RetryMiddleware: retries transient exceptions using fixed/linear/exponential backoff strategies and records attempt counts inctx.metadata(key:retries.attempt).
How it works (quick notes)
- Middleware are composed into a
MiddlewareChainand invoked around acore_handlerthat performs the LLM call. Order matters:PIIRedactionMiddlewaremust appear before the LLM call to ensure the provider receives a sanitized prompt. - Redaction strategy mutates
ctx.raw_inputfor downstream consumers and restores the original value afterward; logs record the redacted input so you can verify what was sent to the provider. - Rate limit and token budget middleware keep small in-memory state in the demo; in production you should replace these with persistent backends (Redis/Postgres) if you need cross-process limits.
Testing and examples
- Demo server: see
tests/guardrails/test_middleware.pywhich builds a demo chain, exposes a FastAPI/askendpoint, and includes amock_llmpath useful for retry testing. - PII redaction check: call the
/askendpoint with an input containing an email/phone and inspect the server logs — the log line for the LLM prompt should show[REDACTED_EMAIL]/[REDACTED_PHONE]. - Retry testing: the demo
mock_llmsimulates a transientTimeoutErroron the first attempt foruser_id == "retry_test", allowing you to observe retry attempts in the logs and the final successful response. - Rate-limit & token-budget: adjust the constructor parameters in the demo to lower limits for testing, and choose
raise_on_exceed=Falseto have the middleware return a blockedAgentResponserather than raising.
Programmatic assertions
- Direct chain call: call the
CHAINinstance from the demo to assert retry counts and blocked responses in unit tests. - Pytest example (suggested): create an async test that runs
CHAINwithuser_id='retry_test'and assertsctx.metadata['retries.attempt'] >= 1and that the finalAgentResponseis not blocked.
Notes
- Real LLM providers require API keys (
HUGGINGFACE_API_KEY, etc.); the demo uses a mock or local provider for safe testing. - The middleware implementations in
abstractions.guardrails.middlewareare intentionally simple; extend them for persistent stores, richer redaction rules, or external monitoring as needed.
Examples
Customer Support (single-agent CLI)
py -m examples.customer_support.main
The example runs a single support_agent that uses tools and optional persistent memory. (No workflow or orchestration required.)
Research + Write (manual chaining)
You can run multiple agents from application code and pass outputs between them:
researcher = create_agent(name="researcher", role="web researcher", llm=llm, tools=get_tools(["web_search"]))
writer = create_agent(name="writer", role="technical writer", llm=llm, tools=get_tools(["file_writer"]))
research_out = await researcher.nw_run("Find benefits of vector search")
write_out = await writer.nw_run(research_out.output)
Environment Variables
| Variable | Required | Description |
|---|---|---|
OPENAI_API_KEY |
If using OpenAI | OpenAI API key |
ANTHROPIC_API_KEY |
If using Anthropic | Anthropic API key |
GOOGLE_API_KEY |
If using Google | Google Gemini API key |
HUGGINGFACE_API_KEY |
If using HuggingFace | HuggingFace API key |
POSTGRES_URL |
If using Postgres memory | postgresql://user:pass@host:5432/db |
REDIS_URL |
If using Redis memory | redis://localhost:6379 |
LANGSMITH_API_KEY |
If using tracing | LangSmith API key |
LANGSMITH_PROJECT |
If using tracing | LangSmith project name |
LOG_LEVEL |
No (default: INFO) | DEBUG, INFO, WARNING, ERROR |
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file netweb_adk-0.1.6.tar.gz.
File metadata
- Download URL: netweb_adk-0.1.6.tar.gz
- Upload date:
- Size: 68.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
808a22109e884d2d442d3b7cb684ff8df6ddd79bc2f850d2a5d836a457474570
|
|
| MD5 |
f9fc5a8d48fa689755ebc2863d7c3304
|
|
| BLAKE2b-256 |
75d8fa6d3262a9c9244706beeca6c58d27931edf841790dde2d1e391f339c6b0
|
File details
Details for the file netweb_adk-0.1.6-py3-none-any.whl.
File metadata
- Download URL: netweb_adk-0.1.6-py3-none-any.whl
- Upload date:
- Size: 99.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a93c833dbdc197890e96de7488ad998210c20957a9631e81f8dd4d1518b41552
|
|
| MD5 |
8d014dadde7974d78f330729343cd8b0
|
|
| BLAKE2b-256 |
d698216423c11616ec0a283b91389a6787bf13043b6c87d78862197052b733e7
|