ollama/docs/ENTRYPOINT_FEATURE.md

212 lines
6.0 KiB
Markdown

# ENTRYPOINT Feature for Ollama Agents
## Overview
The ENTRYPOINT command allows agents to specify an external program to run instead of the built-in Ollama chat loop. This makes Ollama a packaging/distribution mechanism for agents with custom runtimes.
## Status: Implemented ✓
## What Was Done
### 1. Types & API
**`types/model/config.go`**
- Added `Entrypoint string` field to `ConfigV2` struct
**`api/types.go`**
- Added `Entrypoint string` to `CreateRequest` (line ~576)
- Added `Entrypoint string` to `ShowResponse` (line ~632)
### 2. Parser
**`parser/parser.go`**
- Added "entrypoint" to `isValidCommand()` switch
- Added case in `CreateRequest()` to set `req.Entrypoint = c.Args`
- Updated `ParseFile()` to allow ENTRYPOINT without FROM (entrypoint-only agents)
- Added entrypoint serialization in `Command.String()`
### 3. Server
**`server/create.go`**
- Added `config.Entrypoint = r.Entrypoint` to store entrypoint in config
- Made FROM optional when ENTRYPOINT is specified:
```go
} else if r.Entrypoint != "" {
// Entrypoint-only agent: no base model needed
slog.Debug("create entrypoint-only agent", "entrypoint", r.Entrypoint)
}
```
**`server/routes.go`**
- Added `Entrypoint: m.Config.Entrypoint` to ShowResponse in `GetModelInfo()`
**`server/images.go`**
- Added entrypoint serialization in `Model.String()`:
```go
if m.Config.Entrypoint != "" {
modelfile.Commands = append(modelfile.Commands, parser.Command{
Name: "entrypoint",
Args: m.Config.Entrypoint,
})
}
```
### 4. CLI
**`cmd/cmd.go`**
- Added `Entrypoint string` to `runOptions` struct
- Updated agent detection to include Entrypoint check
- Added entrypoint check before interactive mode:
```go
if opts.Entrypoint != "" {
return runEntrypoint(cmd, opts)
}
```
- Implemented `runEntrypoint()` function:
- Parses entrypoint into command and args
- Appends user prompt as additional argument if provided
- Looks up command in PATH
- Creates subprocess with stdin/stdout/stderr connected
- Runs and waits for completion
- Updated `showInfo()` to display entrypoint in Agent section
- Updated `showInfo()` to hide Model section for entrypoint-only agents (no blank fields)
- Added `$PROMPT` placeholder support in `runEntrypoint()`:
- If entrypoint contains `$PROMPT`, it's replaced with the user's prompt
- If no placeholder, prompt is appended as positional argument (backwards compatible)
- If no prompt provided, `$PROMPT` is removed from the command
## Usage
### Agentfile
```dockerfile
# Minimal entrypoint agent (no model required)
ENTRYPOINT ducky
# Or with full path
ENTRYPOINT /usr/local/bin/ducky
# Or with arguments
ENTRYPOINT ducky --verbose
# Use $PROMPT placeholder to control where prompt is inserted
ENTRYPOINT ducky -p $PROMPT
# Without placeholder, prompt is appended as positional argument
ENTRYPOINT echo "Hello" # becomes: echo "Hello" <prompt>
# Can still bundle skills/MCPs with entrypoint agents
SKILL ./my-skill
MCP calculator python3 ./calc.py
ENTRYPOINT my-custom-runtime
```
### CLI
```bash
# Create the agent
ollama create ducky -f ducky.Agentfile
# Run it - starts the entrypoint (e.g., REPL)
ollama run ducky
# With prompt (passed as argument to entrypoint)
ollama run ducky "hello"
# Show agent info
ollama show ducky
# Agent
# entrypoint ducky
```
## Testing Done
1. **Basic entrypoint execution**: ✓
```bash
# Agentfile: ENTRYPOINT echo "Hello from entrypoint"
ollama run test-entry # Output: "Hello from entrypoint"
```
2. **Prompt passing (positional)**: ✓
```bash
# Agentfile: ENTRYPOINT echo "Args:"
ollama run echo-test "hello world" # Output: "Args:" hello world
```
3. **Prompt passing ($PROMPT placeholder)**: ✓
```bash
# Agentfile: ENTRYPOINT echo "Prompt was:" $PROMPT "end"
ollama run echo-placeholder "hello world" # Output: "Prompt was:" hello world "end"
ollama run echo-placeholder # Output: "Prompt was:" "end"
```
4. **Show command**: ✓
```bash
ollama show ducky
# Agent
# entrypoint ducky
# (Model section hidden for entrypoint-only agents)
```
5. **List command**: ✓
- Entrypoint-only agents show with small sizes (~200 bytes)
## Left Over / Future Enhancements
### 1. Context Passing via Environment Variables
Pass agent context to entrypoint via env vars:
- `OLLAMA_AGENT_NAME` - Name of the agent
- `OLLAMA_SKILLS_PATH` - Path to bundled skills
- `OLLAMA_MCPS` - JSON of MCP configurations
### ~~2. Arguments Placeholder~~ ✓ DONE
~~Support placeholder syntax for more control:~~
```dockerfile
# Now supported!
ENTRYPOINT ducky -p $PROMPT
```
### 3. Working Directory
Set working directory for entrypoint:
```dockerfile
WORKDIR /app
ENTRYPOINT ./run.sh
```
### 4. Interactive Mode Detection
Different behavior for REPL vs single-shot:
- Detect if stdin is a TTY
- Pass different flags based on mode
### 5. Signal Handling
Improved signal forwarding to subprocess:
- Forward SIGINT, SIGTERM gracefully
- Handle cleanup on parent exit
### 6. Entrypoint with Model
Allow both model and entrypoint:
```dockerfile
FROM llama3.2
ENTRYPOINT my-custom-ui
```
The entrypoint could then use the model via Ollama API.
### 7. Pull/Push for Entrypoint Agents
- Currently entrypoint agents can be created locally
- Need to test/verify push/pull to registry works correctly
- May need to handle entrypoint binaries (or just reference system commands)
### 8. Error Handling
- Better error messages when entrypoint command not found
- Validation of entrypoint during create (optional, warn if not found)
## Design Decisions
1. **Subprocess mode (not exec)**: Ollama stays as parent process to handle signals and cleanup
2. **No context passing initially**: Keep it simple, entrypoint handles its own config
3. **Skills/MCPs allowed**: Enables packaging assets with the agent even if entrypoint manages execution
4. **FROM optional**: Entrypoint agents don't need a model, just the runtime
5. **Prompt as argument**: User prompt is appended as argument to entrypoint command (simplest approach)