10 Commits
Author SHA1 Message Date
Serply 407e564b91 feat(tools): add Serply as a web_search provider (#1567)
* feat(tools): add Serply as a web_search provider

Serply is a SERP API returning Google web results on a tenant-supplied
key. It joins the existing chain the same way Exa, Tavily and Brave do:
keyed from config_secrets, skipped silently when no key is stored, and
selectable through the provider parameter for cross-engine corroboration.

Freshness maps onto Google's tbs recency filter, which Serply forwards
upstream. Only the pd/pw/pm/py shortcuts are sent: upstream ignores the
equivalent cdr date range and answers with unfiltered results, so a
range leaves tbs unset rather than naming a filter the results do not
honour.

The settings form gained a fifth sortable provider, so the locked
DuckDuckGo card now derives its position number instead of hardcoding
it, and a stored provider_order is reconciled against the full provider
list rather than against Parallel alone.

* test(tools): use a locally named round trip stub in the serply test

The serply cancellation test borrowed parallelRoundTripFunc from
web_search_parallel_test.go. Define serplyRoundTripFunc alongside the
test that uses it so the file does not depend on another provider's
test helper.
2026-09-26 10:33:07 +07:00
georgeatparallel eef6f27775 feat(tools): add optional Parallel web search provider
Signed-off-by: georgeatparallel <george@parallel.ai>
2026-08-02 05:31:39 -07:00
mozaa cfb7f46324 feat(web_search): add provider arg to force a specific engine (#1108)
Currently the web_search tool resolves a tenant-configured provider
chain (e.g. tavily → exa → brave) and stops at the first success.
That's the right default for cost/latency, but it makes cross-engine
corroboration impossible at the agent level: the caller has no way to
ask "search the same query on Exa specifically" once Tavily has
already returned a hit.

Add an optional `provider` argument. When set, the chain is narrowed
to the named provider (case-insensitive); other providers are not
queried. The first-success-wins fallback is preserved when the arg
is omitted.

Use case (concrete): a research agent verifying source freshness
calls web_search twice for the same query — once with provider="tavily"
and once with provider="exa" — and compares the URLs returned. URLs
that appear in both engines are high-confidence original primary
sources; URLs only in one signal a republish or low-circulation outlet
worth verifying further.

Other changes:

  - Cache key now includes the requested provider so per-engine
    results don't collide. Without this, the second call would just
    replay the first engine's cached result, defeating the purpose.
  - Unknown provider returns a clear error listing what IS configured
    for the tenant — better DX than a silent no-op.

Tests: 5 new cases covering narrowing, case-insensitivity, unknown
provider, default first-success behaviour preservation, and cache
isolation across providers.
2026-06-25 16:59:48 +07:00
viettranx 31a6d1a60c refactor(tools): convert web_search to tenant-scoped provider resolution
Refactor WebSearchTool constructor to accept ConfigSecretsStore and
MessageBus instead of hardcoded WebSearchConfig. Implement runtime
per-tenant provider chain resolution via tenantChainCache.

Constructor now:
- Subscribes to cache invalidation events on config_secrets changes
- Returns nil-safe tool instance (no early return on empty providers)
- Passes secrets store and bus for dynamic resolution per Execute() call

Add resolve unit tests; delete legacy config_test.go (functionality
subsumed by cache tests and integration tests).
2026-04-18 17:47:21 +07:00
viettranx 30a40bbe59 feat(tools): add Exa + Tavily web search providers with ranked ordering
Port Exa and Tavily provider clients from PR #825 into the tenant-aware
overlay architecture (builtin_tool_tenant_configs.settings).

- Add ExaConfig + TavilyConfig to WebToolsConfig with provider_order
- Add Exa HTTP client (api.exa.ai/search, x-api-key auth)
- Add Tavily HTTP client (api.tavily.com/search, Bearer auth)
- Extend Brave + DDG constructors with per-provider maxResults
- Add config_secrets plumbing for exa/tavily API keys (apply/collect/mask/strip)
- Refactor gateway_setup.go to use WebSearchConfigFromConfig
- Add NormalizeWebSearchProviderOrder (DDG always last, dedup, unknown skip)
- Extract web_search_config.go (builder, normalizer, shared helpers)
- 11 new unit tests for provider order, builder, clamp, normalize

Credit: @kaitranntt (PR #825) for the original Exa + Tavily implementation.
2026-04-12 11:09:32 +07:00
viettranx fbbba5e8bb feat(tools): tenant-aware web_search provider chain resolution
Refactor web_search Execute to resolve its provider chain per-request
via BuiltinToolSettingsFromCtx instead of iterating the singleton's
hardcoded provider list. Tenant admins can now reorder or disable
providers via builtin_tool_tenant_configs.settings using the shape
{"provider_order":[...], "brave":{"enabled":false}, ...}. Unknown
provider names in provider_order are logged + skipped — no injection
path via this settings blob. Malformed JSON falls back to defaults
(fail-open so a bad admin paste never crashes the tool). Secrets stay
in config_secrets — tenant cannot inject API keys through this path.
11 unit tests cover reorder, filter, disable, unknown-skip, malformed,
global-layer, and tenant-vs-global precedence.

Note: This is the MVP tenant adoption half of the plan's Phase 7. The
Exa + Tavily feature port from PR 825 and coordination with its author
is deferred to a separate follow-up (the port is net-new feature work
orthogonal to the overlay adoption).
2026-04-12 09:01:01 +07:00
viettranx bdb60de7ae chore: upgrade Go 1.25 → 1.26 and apply go fix modernizations
- Update go.mod and Dockerfile to Go 1.26
- Apply `go fix ./...` stdlib modernizations across 170+ files
- Add `go fix` to post-implementation checklist in CLAUDE.md
- Fix go fix misapplied rewrite in loop_history.go
2026-03-10 00:09:15 +07:00
Nam Nguyen NgocandNam Nguyen Ngoc b901a82551 fix(security): harden web fetch/search against prompt injection and cache poisoning (#80)
- Scan web_fetch/web_search tool results for prompt injection patterns via inputGuard
- Strip hidden HTML elements (display:none, aria-hidden, sr-only classes) during conversion
- Scope web tool caches per channel to prevent cross-channel cache poisoning
- Enforce domain blocklist and allowlist checks on HTTP redirect targets
- Add untrusted content reminder to external content wrapper
- Log redirect source URL in fetch results for transparency

Co-authored-by: Nam Nguyen Ngoc <namnn.0911@gmail.com>
2026-03-07 19:31:56 +07:00
viettranxandClaude Opus 4.6 50a90aa8c6 refactor: split large Go files (>350 lines) into smaller same-package files
Pure file reorganization — no logic changes, no renames, no refactoring.
Functions moved to new files in the same package for maintainability.

Split 13 files across 6 packages into 25 new files:
- store/pg: teams.go → teams_tasks/delegation/messaging.go; mcp_servers.go → mcp_servers_access.go
- tools: delegate.go → delegate_state/policy/events.go; subagent.go → subagent_exec/config.go;
  web_search.go → web_search_brave/ddg.go; web_fetch.go → web_fetch_convert.go;
  sessions.go → sessions_history/send.go
- providers: anthropic.go → anthropic_stream/request.go
- mcp: manager.go → manager_connect/tools/util.go
- channels/feishu: bot.go → bot_parse/policy.go; larkclient.go → larkclient_messaging.go
- cmd: gateway_consumer.go → gateway_cron.go; agent_chat.go → agent_chat_client/standalone.go

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 17:27:28 +07:00
Viet TranandClaude Opus 4.6 f3f4c67b36 Initial commit: GoClaw AI agent gateway
Multi-agent AI gateway with WebSocket RPC, HTTP API, and messaging channel integrations.
Go port of OpenClaw with multi-tenant PostgreSQL, per-user isolation, security hardening,
and production observability.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 14:58:07 +07:00