> ## Documentation Index
> Fetch the complete documentation index at: https://docs.clypt.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Semantic Operators

> SentimentParser, WebSearchOperator, LLMScorer

## Overview

This page documents **3 operators** (role: various).

***

## LLMScorer

Generate trading signals from numeric indicators using an LLM.

Feeds one or more numeric indicators (e.g., RSI, MACD, sentiment) into an
LLM and returns a trading signal in the range \[-1, 1]. This operator is a
pure scorer -- it has no access to tools or external APIs. If you need web
search data, pipe WebSearchOperator output through SentimentParser first
and feed the result here. LLM calls are routed through BlackboxAI and
require a BLACKBOX\_API\_KEY environment variable. Duplicate prompts across
symbols are deduplicated so the LLM is called only once per unique prompt.
A configurable call\_interval lets you skip LLM calls on intermediate ticks
and reuse the most recent cached scores.

**Role**: `UNKNOWN` | **Ephemeral**: Yes

### Parameters

| Parameter              | Type                  | Default         | Description                                                   |
| ---------------------- | --------------------- | --------------- | ------------------------------------------------------------- |
| `inputs`               | `List[Input]`         | Required        | List of Input signals (numeric indicators such as RSI, MACD). |
| `input_names`          | `Optional[List[str]]` | `None`          | Human-readable names for each input, used in the LLM prompt   |
| `model`                | `str`                 | `'deepseek-v3'` | LLM model name                                                |
| `api_key`              | `Optional[str]`       | `None`          | BlackboxAI API key                                            |
| `system_prompt`        | `Optional[str]`       | `None`          | Custom system prompt for the LLM                              |
| `user_prompt_template` | `Optional[str]`       | `None`          | Custom user prompt template; use \{symbol},                   |
| `call_interval`        | `int`                 | `1`             | Call the LLM every N ticks; intermediate ticks return         |
| `output_timeframe`     | `Optional[str]`       | `None`          | Output timeframe                                              |
| `_provider`            | `str`                 | `'blackbox'`    |                                                               |

### Usage

```python theme={null}
# Combine technical indicators with LLM judgment
graph.add_node("signal", LLMScorer(
    inputs=[
        Input("rsi", timeframe="1h", lookback=1),
        Input("macd", timeframe="1h", lookback=1),
        Input("sentiment", timeframe="1h", lookback=1),
    ],
    input_names=["RSI", "MACD", "Sentiment"],
    model="claude-3-haiku",
    system_prompt="You are a quant trader. Analyze indicators and give signal.",
    call_interval=10,  # Only call LLM every 10 ticks
))
```

<sub>Source: `apps/trading/operators/semantic/llm_scorer.py`</sub>

***

## SentimentParser

Parse text input and output sentiment scores.

Converts text (e.g., from WebSearchOperator) into numeric sentiment scores
in the range \[-1, 1] using either an LLM or a rule-based keyword matcher.
LLM-based analysis routes through BlackboxAI and requires a BLACKBOX\_API\_KEY
environment variable. Rule-based mode ("rule-based") uses local keyword
matching with no API calls. Duplicate input texts are deduplicated so that
the LLM is called only once per unique text.

**Role**: `UNKNOWN` | **Ephemeral**: Yes

### Parameters

| Parameter              | Type            | Default         | Description                                                           |
| ---------------------- | --------------- | --------------- | --------------------------------------------------------------------- |
| `text_input`           | `Input`         | Required        | Input containing text to analyze. timeframe specifies data frequency. |
| `model`                | `str`           | `'deepseek-v3'` | Model name for sentiment analysis                                     |
| `api_key`              | `Optional[str]` | `None`          | BlackboxAI API key                                                    |
| `system_prompt`        | `Optional[str]` | `None`          | Custom system prompt for the LLM                                      |
| `user_prompt_template` | `Optional[str]` | `None`          | Custom user prompt template; use \{text} as placeholder               |
| `output_timeframe`     | `Optional[str]` | `None`          | Output timeframe                                                      |
| `_provider`            | `str`           | `'blackbox'`    |                                                                       |

### Usage

```python theme={null}
# Parse sentiment from news
graph.add_node("sentiment", SentimentParser(
    text_input=Input("news", timeframe="1h", lookback=1),
    model="claude-3-haiku",
))

# Use rule-based sentiment (no API calls)
graph.add_node("sentiment_fast", SentimentParser(
    text_input=Input("news", timeframe="1h", lookback=1),
    model="rule-based",
))
```

<sub>Source: `apps/trading/operators/semantic/sentiment.py`</sub>

***

## WebSearchOperator

Collect web search results as a Tagged Tensor.

Executes web searches via the WebSearchClient and returns results as a
Tagged Tensor whose value is 1.0 when results are found and 0.0 otherwise.
Requires a BLACKBOX\_API\_KEY environment variable. Supports per-symbol
queries (use \{symbol} in query\_template), aggregated multi-symbol queries,
and single global queries. An optional gate input can suppress searches
when its value is below 0.5. Results may be cached to reduce API calls.
The output is ephemeral and cannot be referenced with lookback above 1.

**Role**: `UNKNOWN` | **Ephemeral**: Yes

### Parameters

| Parameter          | Type              | Default    | Description                                                    |
| ------------------ | ----------------- | ---------- | -------------------------------------------------------------- |
| `query_template`   | `str`             | Required   | Search query template. Use \{symbol} for per-symbol queries.   |
| `gate_input`       | `Optional[Input]` | `None`     | Optional gate input; search is skipped when gate value \<= 0.5 |
| `num_results`      | `int`             | `5`        | Number of search results to return per query                   |
| `provider`         | `str`             | `'serper'` | Search provider name, kept for backward compatibility          |
| `api_key`          | `Optional[str]`   | `None`     | API key for search provider                                    |
| `cache_results`    | `bool`            | `True`     | Whether to cache search results locally                        |
| `cache_dir`        | `Optional[str]`   | `None`     | Directory for the result cache                                 |
| `cache_ttl`        | `int`             | `3600`     | Cache time-to-live in seconds                                  |
| `per_symbol`       | `bool`            | `True`     | If True, issue a separate query per symbol; if False, run a    |
| `aggregate_open`   | `bool`            | `True`     | If True and per\_symbol is True, combine all open symbols      |
| `output_timeframe` | `Optional[str]`   | `None`     | Output timeframe                                               |

### Usage

```python theme={null}
# Search for news about each symbol
graph.add_node("news", WebSearchOperator(
    query_template="cryptocurrency {symbol} market news",
    num_results=3,
    cache_results=True,
))

# Use gate to conditionally search
graph.add_node("news_conditional", WebSearchOperator(
    query_template="BTC breaking news",
    gate_input=Input("volatility_gate", timeframe="1h", lookback=1),
))
```

<sub>Source: `apps/trading/operators/semantic/websearch.py`</sub>

## Related Pages

<CardGroup cols={2}>
  <Card title="Operator Protocol" icon="gear" href="/engine/operator-protocol">
    How operators implement the compute() interface
  </Card>

  <Card title="StatefulGraph" icon="diagram-project" href="/engine/stateful-graph">
    How operators compose into a DAG
  </Card>
</CardGroup>
