Download the PHP package tivins/llm-lib without Composer
On this page you can find all versions of the php package tivins/llm-lib. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Informations about the package llm-lib
llm-lib
PHP library for building LLM agents and calling OpenAI-compatible HTTP APIs — chat completions, embeddings, rerank, and tokenize (OpenAI, Ollama, vLLM, llama.cpp, LiteLLM, etc.).
Namespace: Tivins\LlmLib
Package: tivins/llm-lib
PHP: ^8.3
Current version: see CHANGELOG.md
Table of contents
- What this library does
- Architecture
- Quick start
- Core concepts
- Agent lifecycle hooks
- Behavioral contracts
- Examples
- Backend compatibility
- Project layout
- Development
What this library does
| Responsibility | Class | File |
|---|---|---|
HTTP client (/v1/chat/completions, /v1/embeddings, /v1/rerank, /tokenize) |
LLM |
src/LLM.php |
| Message history | Conversation |
src/Conversation.php |
| Single turn: LLM ↔ tools loop | Agent |
src/Agent.php |
| Tool definitions + handlers | ToolRegistry, Tool, ToolSchema |
src/ToolRegistry.php, … |
| Skipped tool call payloads | ToolCallRejection |
src/ToolCallRejection.php |
| Request parameters (chat) | ChatCompletionOptions |
src/ChatCompletionOptions.php |
| Request parameters (embeddings) | EmbeddingOptions |
src/EmbeddingOptions.php |
| Request parameters (rerank) | RerankOptions |
src/RerankOptions.php |
| Chat response | ChatCompletionResponse |
src/ChatCompletionResponse.php |
| Embeddings response | EmbeddingResponse, Embedding |
src/EmbeddingResponse.php, … |
| Rerank response | RerankResponse, RerankResult |
src/RerankResponse.php, … |
| Turn outcome | AgentTurnResult |
src/AgentTurnResult.php |
| Optional JSON persistence | Logger |
src/Logger.php |
| Observability / extension points | AgentHooks |
src/AgentHooks.php |
Not included: streaming, model management endpoints (stubs exist as comments in LLM.php), multi-agent orchestration, vector indexing, or a built-in chat UI.
Architecture
Agent turn
One agent turn (Agent::runTurn()):
- Dispatch
BeforeTurn. - Call the LLM with the current conversation.
- If the assistant message contains
tool_calls, execute each tool, append tool messages, and call the LLM again. - Repeat until the model stops with
finish_reason: stop(orlengthwithout tool calls — see behavioral contracts). - Store the final assistant message in the conversation.
- Dispatch
AfterTurnand returnAgentTurnResult.
RAG pipeline (typical use of embeddings + rerank)
Embeddings and rerank are standalone LLM calls — they do not go through Agent. A common retrieval pipeline looks like:
Quick start
Install
Minimal agent (text response)
Agent with tools
Handlers receive the raw JSON arguments string from the model and must return a string (usually JSON) used as the tool message content.
Embeddings
Rerank
Use a reranker model on a server started with --reranking — do not call /v1/embeddings with a reranker (scores will be meaningless).
Conversation logging
Core concepts
Message
A chat message with role, content, optional reasoningContent, toolCalls, toolCallId, and meta.
Two serialization methods exist on purpose:
| Method | Purpose |
|---|---|
toArray() |
Internal storage, logs, JsonSerializable — keeps reasoning_content and meta |
toChatCompletionArray() |
Payload sent to the API — omits reasoning_content and meta |
Conversation
Ordered list of Message objects. toChatCompletionArray() maps every message through Message::toChatCompletionArray().
ChatCompletionOptions
Per-request settings: model, temperature, topP, n, tools, toolChoice, responseFormat.
Important: Agent::runTurn() injects $options->tools = $this->tools (mutates the object in place). Passing a different ToolRegistry in options throws InvalidArgumentException.
AgentTurnResult
LLM
Shared HTTP client. Endpoint is the base URL without trailing /v1; paths are appended per method.
| Method | Endpoint | Input |
|---|---|---|
chatCompletion() |
POST /v1/chat/completions |
Conversation + ChatCompletionOptions |
embeddings() |
POST /v1/embeddings |
string\|list<string> + EmbeddingOptions |
rerank() |
POST /v1/rerank |
query, list<string> documents + RerankOptions |
tokenize() |
POST /tokenize |
string (llama.cpp) |
Common behaviour:
- Optional
apiKey→Authorization: Bearerheader. - Configurable
timeoutSeconds(default 120). - Throws
Exceptionon cURL failure, HTTP ≥ 400, or malformed JSON. - Returns
durationin milliseconds on response objects.
Chat-specific: chatCompletion() normalizes GPT-OSS / Harmony <|channel|> markers in assistant responses and can recover usable text from llama.cpp Harmony parse errors (HTTP 500).
Embeddings-specific: vectors are returned as float[]. When the API returns base64-encoded vectors (encoding_format: base64), they are decoded automatically.
Rerank-specific: RerankResponse::sortedResults() returns results by descending score; rankedDocuments($documents) maps scores back to the original document strings.
EmbeddingOptions / EmbeddingResponse
EmbeddingOptions:model,encodingFormat(floatorbase64),dimensions(OpenAI embedding v3).EmbeddingResponse:model,usage,embeddings[],first(),vectors(),raw().- Each
Embeddinghasindexandvector(list<float>).
RerankOptions / RerankResponse
RerankOptions:model,topN(sent astop_n; limits how many results the server returns).RerankResponse:model,usage,results[],sortedResults(),rankedDocuments(),raw().- Each
RerankResulthasindex(position in the inputdocumentsarray) andrelevanceScore.
ToolRegistry
registerTools()adds or overwrites tools by name (last registration wins).execute()runs the handler or returns a tool message with{"error":"No handler for tool: …"}(no exception).
Agent lifecycle hooks
Register listeners on AgentHooks (fluent API). Events are defined in AgentHookEvent:
| Event | When | Notable payload |
|---|---|---|
BeforeTurn |
Start of runTurn() |
BeforeTurnEvent |
AfterTurn |
End of runTurn() |
AfterTurnEvent + AgentTurnResult |
BeforeLlmCall / AfterLlmCall |
Around each API call | toolRound index |
BeforeToolRound / AfterToolRound |
Around each batch of tool executions | tool calls / tool messages |
BeforeToolCall / AfterToolCall |
Per tool call | BeforeToolCallEvent::$replacement can skip execution |
OnMaxToolRoundsExceeded |
maxToolRounds reached |
turn fails after this |
OnAssistantResponse |
Before storing final assistant message | OnAssistantResponseEvent::$visibleContent can rewrite content |
See also todo_tool_approval.md for tool-approval patterns in a code harness.
Behavioral contracts
These behaviors are intentional and covered by unit tests. Open questions live in TODO.md.
Empty content
- Stored as
''inMessage::$contentandtoArray(). - Sent to the API as
nullintoChatCompletionArray()(OpenAI format).
reasoning_content
- Parsed from API responses and kept in
Message::$reasoningContent. - Included in
toArray()for logging. - Never sent back in subsequent requests via
toChatCompletionArray().
Unknown tool
No handler → tool message with JSON error content; conversation continues (model may recover).
Duplicate tool name
registerTools() silently overwrites the previous handler for the same name.
finish_reason: length
If the model stops due to token limit without pending tool calls, the turn is treated as success (truncated content is stored). Check message->meta['finish_reason'] if you need to detect truncation.
Assistant message metadata
Stored assistant messages include meta with at least created_at, time_ms, model, usage, finish_reason, and temperature (from options).
Examples
Runnable scripts in examples/. Numbering leaves gaps (ex011, …) for future additions.
| File | Topic |
|---|---|
ex010-chat-completion.php |
Single-turn chat, no agent |
ex020-multi-turn-memory.php |
Multi-turn conversation |
ex030-agent-no-tools.php |
Minimal agent |
ex040-single-tool.php |
One tool round |
ex050-multi-tool-hooks.php |
Hooks around tool execution |
ex060-multi-turn-agent.php |
Agent over several turns |
ex070-advanced-hooks.php |
Advanced hook usage |
ex080-api-edge-cases.php |
API edge cases |
ex090-tokenize-phrases.php |
Phrase-level tokenize comparison |
ex100-tokenize-words.php |
Word-level tokenize comparison |
ex110-tool-proposal-rejected.php |
Reject a tool call via hook |
ex120-embeddings.php |
Batch embeddings + cosine similarity |
ex130-rerank.php |
Rerank documents for a query |
Backend compatibility
| Backend | Chat | Embeddings | Rerank | Tokenize |
|---|---|---|---|---|
| OpenAI | /v1/chat/completions |
/v1/embeddings |
— | — |
| Ollama | /v1/chat/completions |
/v1/embeddings |
— (no stable native API) | — |
| llama.cpp | /v1/chat/completions |
/v1/embeddings |
/v1/rerank |
/tokenize |
| vLLM / LiteLLM | yes | yes (proxy) | depends on upstream | — |
Notes:
- Embeddings follow the OpenAI Embeddings API (
input,model, optionalencoding_format,dimensions). - Rerank follows the llama.cpp / Jina-style API (
query,documents, optionaltop_n). Requires a dedicated reranker model with--reranking --embedding --pooling rank. - Multiple servers: point each
LLMinstance at a differentendpoint/defaultModel(chat on:8080, embeddings on:8081, rerank on:8082, etc.).
Project layout
Development
Extending LLM
The library uses a concrete LLM class (not an interface). For tests or custom transports:
- Subclass and override
protected function request(...)— seetests/LLMTest.php(CapturingLLM). - Substitute a test double with compatible methods — see
tests/Support/StubLLM.php(chatCompletion,embeddings,rerank,tokenize).
Contributing
- Add or update tests for behavior changes.
- Run
composer analyseandcomposer test. - Document intentional behavior in this README or
TODO.md. - Update
CHANGELOG.mdunder[Unreleased].
License
MIT — see composer.json.
All versions of llm-lib with dependencies
ext-curl Version *