Skip to content

Targets

pikit.targets

Model backends behind a uniform :class:Target interface.

Attack and defense code never imports a backend SDK directly — it calls :func:get_target and uses :meth:Target.query. Every backend SDK is imported lazily inside its own module, so the core package and the mock target work with zero third-party dependencies installed.

Target

Bases: ABC

A model backend that turns a prompt into a text completion.

Subclasses implement :meth:query. Backends keep their SDK imports local (lazy) so that installing the core package pulls in nothing.

Tool-calling support via :meth:chat is an optional capability: backends that do not implement it raise NotImplementedError, and text-only callers (the direct-injection pipeline, ChatAgent) never need it.

query abstractmethod

query(prompt: str, system: Optional[str] = None, **kwargs) -> str

Send prompt to the backend and return the text response.

Parameters

prompt: The user prompt (typically already attacked and/or defended). system: Optional system prompt. Backends without a native system role should prepend it to the user prompt. **kwargs: Backend-specific generation options (e.g. temperature, max_tokens).

chat

chat(messages: List[Message], tools: Optional[List[dict]] = None, system: Optional[str] = None, **kwargs) -> ChatResponse

Multi-turn, tool-aware completion. Optional capability.

Parameters

messages: The conversation so far as normalized :class:Message objects. tools: Provider-agnostic tool schemas, each a dict shaped like {"name", "description", "parameters": <JSON schema>}. Each backend translates these into its own wire format. system: Optional system prompt.

Returns

ChatResponse Normalized assistant turn (text + any tool calls).

ChatResponse dataclass

ChatResponse(text: str = '', tool_calls: List[ToolCall] = list(), stop_reason: Optional[str] = None, raw: Any = None)

A normalized single assistant turn.

Message dataclass

Message(role: str, content: str = '', tool_calls: List[ToolCall] = list(), tool_results: List[ToolResult] = list())

A turn in the conversation the agent maintains.

role is one of "system", "user", "assistant", "tool". Assistant turns may carry tool_calls; tool turns carry tool_results. Each backend's chat() translates these into its own wire format.

ToolCall dataclass

ToolCall(id: str, name: str, args: Dict[str, Any] = dict())

A model's request to invoke a tool.

ToolResult dataclass

ToolResult(id: str, name: str, content: str)

The result of running a tool, fed back to the model.

get_target

get_target(spec: str, **kwargs) -> Target

Construct a :class:Target from a "backend:model" spec.

Parameters

spec: One of:

* ``"openai:<model>"`` — OpenAI or any OpenAI-compatible endpoint
  (vLLM, Ollama, …); pass ``base_url=`` / ``api_key=`` via kwargs.
* ``"anthropic:<model>"`` — Anthropic Claude.
* ``"hf:<model>"`` — a local HuggingFace ``transformers`` model.
* ``"mock"`` — an offline echo target for the **test suite only**
  (echoes input, never executes an injection; not for demos).

**kwargs: Forwarded to the backend constructor.

Examples

get_target("mock") MockTarget(...)

pikit.targets.base

The :class:Target abstraction shared by every model backend.

Target

Bases: ABC

A model backend that turns a prompt into a text completion.

Subclasses implement :meth:query. Backends keep their SDK imports local (lazy) so that installing the core package pulls in nothing.

Tool-calling support via :meth:chat is an optional capability: backends that do not implement it raise NotImplementedError, and text-only callers (the direct-injection pipeline, ChatAgent) never need it.

query abstractmethod

query(prompt: str, system: Optional[str] = None, **kwargs) -> str

Send prompt to the backend and return the text response.

Parameters

prompt: The user prompt (typically already attacked and/or defended). system: Optional system prompt. Backends without a native system role should prepend it to the user prompt. **kwargs: Backend-specific generation options (e.g. temperature, max_tokens).

chat

chat(messages: List[Message], tools: Optional[List[dict]] = None, system: Optional[str] = None, **kwargs) -> ChatResponse

Multi-turn, tool-aware completion. Optional capability.

Parameters

messages: The conversation so far as normalized :class:Message objects. tools: Provider-agnostic tool schemas, each a dict shaped like {"name", "description", "parameters": <JSON schema>}. Each backend translates these into its own wire format. system: Optional system prompt.

Returns

ChatResponse Normalized assistant turn (text + any tool calls).

pikit.targets.types

Provider-agnostic data structures for tool-calling chat.

These normalize the differences between backends (OpenAI vs Anthropic) so the agent loop never branches on which provider it is talking to. They are plain, zero-dependency dataclasses importable by both targets and agent.

ToolCall dataclass

ToolCall(id: str, name: str, args: Dict[str, Any] = dict())

A model's request to invoke a tool.

ToolResult dataclass

ToolResult(id: str, name: str, content: str)

The result of running a tool, fed back to the model.

ChatResponse dataclass

ChatResponse(text: str = '', tool_calls: List[ToolCall] = list(), stop_reason: Optional[str] = None, raw: Any = None)

A normalized single assistant turn.

Message dataclass

Message(role: str, content: str = '', tool_calls: List[ToolCall] = list(), tool_results: List[ToolResult] = list())

A turn in the conversation the agent maintains.

role is one of "system", "user", "assistant", "tool". Assistant turns may carry tool_calls; tool turns carry tool_results. Each backend's chat() translates these into its own wire format.

pikit.targets.openai_compatible

OpenAI / OpenAI-compatible chat backend.

Works with the official OpenAI API and any OpenAI-compatible server (vLLM, Ollama's /v1 endpoint, LM Studio, …) by pointing base_url at it. The openai package is imported lazily so the core install needs nothing.

Install with::

pip install pikit[openai]

OpenAICompatibleTarget

OpenAICompatibleTarget(model: Optional[str] = None, base_url: Optional[str] = None, api_key: Optional[str] = None, **client_kwargs)

Bases: Target

Chat-completions backend for OpenAI-compatible endpoints.

Parameters

model: Model name (e.g. "gpt-4o" or a local model id served by vLLM). base_url: Override the endpoint for a compatible server. Falls back to $OPENAI_BASE_URL; defaults to the OpenAI API when unset. api_key: API key. Falls back to $OPENAI_API_KEY. Some local servers accept any value.

Notes

Prefer setting OPENAI_API_KEY / OPENAI_BASE_URL in the environment over passing secrets as literals — keys passed as string arguments are easy to leak into shell history, logs, or version control.

pikit.targets.anthropic

Anthropic Claude backend.

The anthropic package is imported lazily so the core install needs nothing.

Install with::

pip install pikit[anthropic]

AnthropicTarget

AnthropicTarget(model: Optional[str] = None, api_key: Optional[str] = None, max_tokens: int = 1024, **client_kwargs)

Bases: Target

Messages-API backend for Anthropic Claude models.

Parameters

model: Model id (e.g. "claude-sonnet-4-6"). api_key: API key; falls back to $ANTHROPIC_API_KEY. max_tokens: Default response cap (Anthropic requires it on every call).

pikit.targets.huggingface

Local HuggingFace transformers backend.

Loads a model locally and generates text. torch and transformers are imported lazily so the core install needs nothing.

Install with::

pip install pikit[hf]

HuggingFaceTarget

HuggingFaceTarget(model: str, device: str = 'auto', max_new_tokens: int = 256, **model_kwargs)

Bases: Target

Local text-generation backend via transformers.

Uses the chat template when the tokenizer provides one, otherwise falls back to feeding the raw prompt.

Parameters

model: HuggingFace model id (e.g. "meta-llama/Llama-3.1-8B-Instruct"). device: "cpu", "cuda", "auto" (default), … max_new_tokens: Default generation length.

pikit.targets.mock

An offline echo target — a test fixture, not a demo backend.

This target only echoes its input and never executes an injection, so it cannot demonstrate whether an attack works — using it to "show" an attack would misrepresent results. Its sole purpose is the offline test suite: deterministic, no API key, no network, no token cost. To actually observe an attack against an agent, use a real model via :func:~pikit.targets.get_target (openai: / anthropic: / hf:); see demos/05_live and demos/06_live_matrix.

The :meth:chat method supports two offline modes so the function-calling loop is fully testable:

  • Scripted — pass script=[ChatResponse, ...]; each chat() call pops the next response. Lets a test drive an exact tool-call sequence.
  • Heuristic — with no script, if tools are offered and none has been called yet, it calls the first tool; once a tool result is in history it returns a final text echoing what it saw. Enough to exercise the loop in tests.

MockTarget

MockTarget(prefix: str = '[mock] ', script: Optional[List[ChatResponse]] = None)

Bases: Target

Returns a deterministic echo of what it received.

Parameters

prefix: Text prepended to the echoed prompt. Handy for asserting in tests that the full pipeline reached the target. script: Optional list of :class:ChatResponse to return from successive chat() calls, for deterministic tool-loop tests.