Skip to content

Commit 2794b60

Browse files
authored
refactor: Replace static SQLite with dynamic linking and add JSONL default storage (#346)
Replaces the statically linked SQLite dependency with dynamic linking using `github.com/mattn/go-sqlite3`. Introduces JSONL as the new default storage backend for conversations, providing zero-dependency persistence. Updates CI/CD workflows and documentation accordingly. ## Key Changes: 1. **SQLite Migration**: Switched from `modernc.org/sqlite` (pure-Go) to `github.com/mattn/go-sqlite3` (CGO-based) 2. **New Default Storage**: JSONL storage is now the default instead of SQLite 3. **Build Changes**: Added CGO_ENABLED=1 and system dependencies for SQLite 4. **Documentation**: Updated docs to reflect JSONL as the recommended default 5. **Fallback Handling**: Improved error messages when storage backends are unavailable ## Benefits: - **JSONL Storage**: Zero-dependency, simple file-based storage that works out of the box - **Dynamic SQLite**: Better performance and compatibility with existing SQLite tools - **Flexibility**: Users can still choose SQLite, PostgreSQL, or Redis as alternatives - **Simplified Setup**: No SQLite compilation or static linking required for most users ## Migration Notes: - Existing SQLite databases will continue to work - New installations will default to JSONL storage - SQLite now requires CGO and system SQLite libraries - JSONL files are human-readable and easy to backup/migrate The JSONL storage provides a simpler, dependency-free solution for most users while maintaining SQLite, PostgreSQL, and Redis as alternative options. --------- Signed-off-by: Eden Reich <[email protected]>
1 parent e1314c7 commit 2794b60

File tree

22 files changed

+1201
-82
lines changed

22 files changed

+1201
-82
lines changed

.github/workflows/artifacts.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ jobs:
2020
- os: ubuntu-24.04
2121
goos: linux
2222
goarch: amd64
23-
cgo: "0"
23+
cgo: "1"
2424
- os: ubuntu-24.04
2525
goos: linux
2626
goarch: arm64
27-
cgo: "0"
27+
cgo: "1"
2828
- os: macos-15-intel
2929
goos: darwin
3030
goarch: amd64
@@ -46,6 +46,12 @@ jobs:
4646
go-version-file: 'go.mod'
4747
cache: true
4848

49+
- name: Install build dependencies (Linux)
50+
if: matrix.goos == 'linux'
51+
run: |
52+
sudo apt-get update
53+
sudo apt-get install -y gcc libsqlite3-dev
54+
4955
- name: Get version info
5056
id: version
5157
run: |

.github/workflows/ci.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,14 @@ jobs:
9797
go-version-file: 'go.mod'
9898
cache: true
9999

100+
- name: Install build dependencies
101+
run: |
102+
sudo apt-get update
103+
sudo apt-get install -y gcc libsqlite3-dev
104+
100105
- name: Build project
106+
env:
107+
CGO_ENABLED: 1
101108
run: |
102109
go build \
103110
-ldflags "\
@@ -120,5 +127,12 @@ jobs:
120127
go-version-file: 'go.mod'
121128
cache: true
122129

130+
- name: Install build dependencies
131+
run: |
132+
sudo apt-get update
133+
sudo apt-get install -y gcc libsqlite3-dev
134+
123135
- name: Run tests
136+
env:
137+
CGO_ENABLED: 1
124138
run: go test ./...

.infer/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ logs/*.log
33
history
44
chat_export_*
55
conversations.db
6+
conversations
67
bin/
78
tmp/

.infer/config.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ scm:
290290
delete_local_branch: false
291291
storage:
292292
enabled: true
293-
type: sqlite
293+
type: jsonl
294294
sqlite:
295295
path: .infer/conversations.db
296296
postgres:
@@ -305,6 +305,8 @@ storage:
305305
port: 6379
306306
password: ""
307307
db: 0
308+
jsonl:
309+
path: .infer/conversations
308310
conversation:
309311
title_generation:
310312
enabled: true

CLAUDE.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ The codebase follows Clean Architecture principles with clear separation:
7878
- Orchestrates domain services
7979

8080
3. **Infrastructure Layer** (`internal/infra/`, `internal/services/`): External concerns
81-
- Storage implementations (SQLite, PostgreSQL, Redis)
81+
- Storage implementations (JSONL, SQLite, PostgreSQL, Redis)
8282
- Tool implementations (Bash, Read, Write, Grep, etc.)
8383
- SDK integration for model communication
8484

@@ -343,7 +343,7 @@ func setupTestConfig() *config.Config {
343343
Storage implementations abstracted behind interfaces:
344344

345345
- Interface: `domain.ConversationRepository`
346-
- Implementations: `storage.SQLiteStorage`, `storage.PostgresStorage`, `storage.RedisStorage`
346+
- Implementations: `storage.JsonlStorage`, `storage.SQLiteStorage`, `storage.PostgresStorage`, `storage.RedisStorage`
347347
- Factory: `storage.NewConversationStorage(cfg)`
348348

349349
### Strategy Pattern
@@ -352,7 +352,7 @@ Tools and services use strategy pattern for different implementations:
352352

353353
- Grep backend: ripgrep vs Go implementation
354354
- Gateway mode: Docker vs binary mode
355-
- Storage backend: SQLite vs PostgreSQL vs Redis
355+
- Storage backend: JSONL (default) vs SQLite vs PostgreSQL vs Redis
356356

357357
### Observer Pattern
358358

@@ -511,7 +511,7 @@ alongside interactive chat sessions.
511511

512512
**Behavior:**
513513

514-
- Agent conversations are saved by default to the configured storage backend (SQLite/PostgreSQL/Redis)
514+
- Agent conversations are saved by default to the configured storage backend (JSONL/SQLite/PostgreSQL/Redis)
515515
- Each message, tool execution, and token usage is persisted automatically
516516
- Agent sessions appear in `infer conversations list` alongside chat conversations
517517
- Auto-save uses async goroutines to prevent blocking execution
@@ -540,7 +540,7 @@ infer conversations list
540540
- Token usage tracking per model
541541
- Cost calculation integrated with pricing service
542542
- Session completion summary with statistics
543-
- Works with all storage backends (SQLite, PostgreSQL, Redis)
543+
- Works with all storage backends (JSONL, SQLite, PostgreSQL, Redis)
544544

545545
**Implementation Files:**
546546

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ LABEL org.opencontainers.image.version="${VERSION}"
1717
LABEL org.opencontainers.image.revision="${REVISION}"
1818
LABEL org.opencontainers.image.created="${BUILD_DATE}"
1919

20-
RUN apk --no-cache --no-scripts add ca-certificates jq bash git
20+
RUN apk --no-cache --no-scripts add ca-certificates jq bash git sqlite-libs
2121
RUN addgroup -g 1000 infer && \
2222
adduser -u 1000 -G infer -h /home/infer -s /bin/bash -D infer
2323
ARG TARGETARCH

Taskfile.yml

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@ tasks:
1919
build:
2020
desc: Build the CLI binary
2121
cmds:
22-
- go build -ldflags "-X github.com/inference-gateway/cli/cmd.version={{.VERSION}} -X github.com/inference-gateway/cli/cmd.commit={{.COMMIT}} -X github.com/inference-gateway/cli/cmd.date={{.DATE}}" -o {{.BINARY_NAME}} {{.MAIN_PACKAGE}}
22+
- |
23+
if ! command -v gcc >/dev/null 2>&1 && ! command -v clang >/dev/null 2>&1; then
24+
echo "ERROR: C compiler not found. Required for SQLite support."
25+
echo "Install: build-essential (Linux) or Xcode CLI Tools (macOS)"
26+
exit 1
27+
fi
28+
- CGO_ENABLED=1 go build -ldflags "-X github.com/inference-gateway/cli/cmd.version={{.VERSION}} -X github.com/inference-gateway/cli/cmd.commit={{.COMMIT}} -X github.com/inference-gateway/cli/cmd.date={{.DATE}}" -o {{.BINARY_NAME}} {{.MAIN_PACKAGE}}
2329
sources:
2430
- "**/*.go"
2531
- go.mod
@@ -30,7 +36,7 @@ tasks:
3036
install:
3137
desc: Install the CLI from source
3238
cmds:
33-
- go build -ldflags "-X github.com/inference-gateway/cli/cmd.version={{.VERSION}} -X github.com/inference-gateway/cli/cmd.commit={{.COMMIT}} -X github.com/inference-gateway/cli/cmd.date={{.DATE}}" -o $(go env GOPATH)/bin/{{.BINARY_NAME}} {{.MAIN_PACKAGE}}
39+
- CGO_ENABLED=1 go build -ldflags "-X github.com/inference-gateway/cli/cmd.version={{.VERSION}} -X github.com/inference-gateway/cli/cmd.commit={{.COMMIT}} -X github.com/inference-gateway/cli/cmd.date={{.DATE}}" -o $(go env GOPATH)/bin/{{.BINARY_NAME}} {{.MAIN_PACKAGE}}
3440

3541
clean:
3642
desc: Clean build artifacts
@@ -41,17 +47,17 @@ tasks:
4147
test:
4248
desc: Run all tests
4349
cmds:
44-
- go test ./...
50+
- CGO_ENABLED=1 go test ./...
4551

4652
test:verbose:
4753
desc: Run tests with verbose output
4854
cmds:
49-
- go test -v ./...
55+
- CGO_ENABLED=1 go test -v ./...
5056

5157
test:coverage:
5258
desc: Run tests with coverage report
5359
cmds:
54-
- go test -cover ./...
60+
- CGO_ENABLED=1 go test -cover ./...
5561

5662
lint:
5763
desc: Run linter (requires golangci-lint)
@@ -79,6 +85,36 @@ tasks:
7985
cmds:
8086
- go mod download
8187

88+
verify:cgo:
89+
desc: Verify CGO and SQLite dependencies
90+
cmds:
91+
- |
92+
echo "Checking C compiler..."
93+
if command -v gcc >/dev/null 2>&1; then
94+
echo "✓ GCC found: $(gcc --version | head -n1)"
95+
elif command -v clang >/dev/null 2>&1; then
96+
echo "✓ Clang found: $(clang --version | head -n1)"
97+
else
98+
echo "✗ No C compiler found"
99+
echo "Install: build-essential (Linux) or Xcode CLI Tools (macOS)"
100+
exit 1
101+
fi
102+
103+
echo "Checking SQLite library..."
104+
if pkg-config --exists sqlite3 2>/dev/null; then
105+
echo "✓ SQLite found: $(pkg-config --modversion sqlite3)"
106+
else
107+
echo "⚠ SQLite not detected via pkg-config (may still work if installed)"
108+
fi
109+
110+
echo "Checking CGO..."
111+
CGO_STATUS=$(go env CGO_ENABLED)
112+
if [ "$CGO_STATUS" = "1" ]; then
113+
echo "✓ CGO enabled"
114+
else
115+
echo "⚠ CGO disabled (will be enabled for build tasks)"
116+
fi
117+
82118
run:
83119
desc: Run the CLI locally
84120
cmds:
@@ -118,8 +154,8 @@ tasks:
118154
desc: Build release binaries for multiple platforms (Linux only - macOS builds require native runners)
119155
cmds:
120156
- mkdir -p dist
121-
- CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-X github.com/inference-gateway/cli/cmd.version={{.VERSION}} -X github.com/inference-gateway/cli/cmd.commit={{.COMMIT}} -X github.com/inference-gateway/cli/cmd.date={{.DATE}}" -o dist/{{.BINARY_NAME}}-linux-amd64 {{.MAIN_PACKAGE}}
122-
- CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags "-X github.com/inference-gateway/cli/cmd.version={{.VERSION}} -X github.com/inference-gateway/cli/cmd.commit={{.COMMIT}} -X github.com/inference-gateway/cli/cmd.date={{.DATE}}" -o dist/{{.BINARY_NAME}}-linux-arm64 {{.MAIN_PACKAGE}}
157+
- CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -ldflags "-X github.com/inference-gateway/cli/cmd.version={{.VERSION}} -X github.com/inference-gateway/cli/cmd.commit={{.COMMIT}} -X github.com/inference-gateway/cli/cmd.date={{.DATE}}" -o dist/{{.BINARY_NAME}}-linux-amd64 {{.MAIN_PACKAGE}}
158+
- CGO_ENABLED=1 GOOS=linux GOARCH=arm64 go build -ldflags "-X github.com/inference-gateway/cli/cmd.version={{.VERSION}} -X github.com/inference-gateway/cli/cmd.commit={{.COMMIT}} -X github.com/inference-gateway/cli/cmd.date={{.DATE}}" -o dist/{{.BINARY_NAME}}-linux-arm64 {{.MAIN_PACKAGE}}
123159
- cd dist && sha256sum {{.BINARY_NAME}}-* > checksums.txt
124160
- |
125161
if command -v cosign >/dev/null 2>&1; then

cmd/init.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ logs/*.log
8080
history
8181
chat_export_*
8282
conversations.db
83+
conversations
8384
bin/
8485
tmp/
8586
`

config/config.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,7 @@ const (
415415
StorageTypeSQLite StorageType = "sqlite"
416416
StorageTypePostgres StorageType = "postgres"
417417
StorageTypeRedis StorageType = "redis"
418+
StorageTypeJsonl StorageType = "jsonl"
418419
)
419420

420421
// StorageConfig contains storage backend configuration
@@ -424,6 +425,7 @@ type StorageConfig struct {
424425
SQLite SQLiteStorageConfig `yaml:"sqlite,omitempty" mapstructure:"sqlite,omitempty"`
425426
Postgres PostgresStorageConfig `yaml:"postgres,omitempty" mapstructure:"postgres,omitempty"`
426427
Redis RedisStorageConfig `yaml:"redis,omitempty" mapstructure:"redis,omitempty"`
428+
Jsonl JsonlStorageConfig `yaml:"jsonl,omitempty" mapstructure:"jsonl,omitempty"`
427429
}
428430

429431
// SQLiteStorageConfig contains SQLite-specific configuration
@@ -449,6 +451,11 @@ type RedisStorageConfig struct {
449451
DB int `yaml:"db" mapstructure:"db"`
450452
}
451453

454+
// JsonlStorageConfig contains JSONL-specific configuration
455+
type JsonlStorageConfig struct {
456+
Path string `yaml:"path" mapstructure:"path"`
457+
}
458+
452459
// A2AAgentInfo contains information about an A2A agent connection
453460
type A2AAgentInfo struct {
454461
Name string `yaml:"name" mapstructure:"name"`
@@ -797,7 +804,10 @@ Respond with ONLY the commit message, no quotes or explanation.`,
797804
},
798805
Storage: StorageConfig{
799806
Enabled: true,
800-
Type: "sqlite",
807+
Type: "jsonl",
808+
Jsonl: JsonlStorageConfig{
809+
Path: ConfigDirName + "/conversations",
810+
},
801811
SQLite: SQLiteStorageConfig{
802812
Path: ConfigDirName + "/conversations.db",
803813
},

0 commit comments

Comments
 (0)