Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
**/*.DS_Store
**/*.zig-cache
# Ignore build directories
*/build/
10 changes: 10 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Contributing

Please write clear commit messages that briefly describe the changes.
For example:

```
Add Cell framework example using C++23 modules
```

Commit messages like "Applying previous commit" should be avoided.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
### Quick Start

A simple command-line client is provided in `agent_client.zig`. Set the `OPENAI_API_KEY` environment variable and run:
A simple command-line client is provided in `agent_client.zig`. Make sure Zig 0.14.1 is installed (see <https://ziglang.org/download/>). Set the `OPENAI_API_KEY` environment variable and run:

```bash
zig run agent_client.zig -- --persona Abbey
Expand Down Expand Up @@ -30,3 +30,6 @@ To predict a probability with the trained model:
zig run local_ml.zig -- predict model.txt 1.2 3.4
```


### Cell Framework Example
This repository now includes a demonstration of the Cell framework using modern C++23 modules. See `cell_framework/README.md` for build instructions.
5 changes: 5 additions & 0 deletions agent_client.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const Agent = @import("./src/agent.zig");

pub fn main() !void {
try Agent.main();
}
14 changes: 7 additions & 7 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});

// ─── Feature flags for conditional compilation ───────────────────────────
// Feature flags for conditional compilation
const options = b.addOptions();
options.addOption(bool, "enable_gpu", b.option(bool, "gpu", "Enable GPU acceleration") orelse detectGPUSupport());
options.addOption(bool, "enable_simd", b.option(bool, "simd", "Enable SIMD optimizations") orelse detectSIMDSupport());
Expand All @@ -20,26 +20,26 @@ pub fn build(b: *std.Build) void {

const exe = b.addExecutable(.{
.name = "abi",
.root_source_file = b.path("src/main.zig"),
.root_source_file = .{ .src_path = .{ .owner = b, .sub_path = "src/main.zig" } },
.target = target,
.optimize = platform_optimize,
});

// ─── Optimization flags ──────────────────────────────────────────────────
// Optimization flags
exe.link_function_sections = true;
exe.link_gc_sections = true;
if (platform_optimize == .ReleaseSmall or platform_optimize == .ReleaseFast) {
exe.root_module.strip = true;
}

// No external dependencies currently required.
// Dependencies
exe.root_module.addOptions("build_options", options);

// ─── Platform-specific dependencies ──────────────────────────────────────
// Platform-specific dependencies
switch (target.result.os.tag) {
.linux => {
exe.linkSystemLibrary("c");
if (b.option(bool, "enable_io_uring", "Enable io_uring support") orelse true) {
if (b.option(bool, "enable_io_uring", "Enable io_uring support") orelse false) {
exe.linkSystemLibrary("uring");
}
},
Expand Down Expand Up @@ -68,7 +68,7 @@ pub fn build(b: *std.Build) void {
const unit_tests = b.addTest(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
.optimize = platform_optimize,
});
unit_tests.root_module.addOptions("build_options", options);
test_step.dependOn(&b.addRunArtifact(unit_tests).step);
Expand Down
35 changes: 35 additions & 0 deletions cell_framework/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
cmake_minimum_required(VERSION 3.26)
project(CellFramework LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API 1)

# Directory for generated headers
set(GENERATED_INCLUDE_DIR ${CMAKE_BINARY_DIR}/include)
file(MAKE_DIRECTORY ${GENERATED_INCLUDE_DIR})

add_custom_target(generate_headers
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/generate_headers.cmake
BYPRODUCTS ${GENERATED_INCLUDE_DIR}/Cell/Core.hpp
VERBATIM
)

add_library(CellCore)

target_sources(CellCore
PUBLIC
FILE_SET cxx_modules TYPE CXX_MODULES FILES
${CMAKE_CURRENT_SOURCE_DIR}/Cell/Core.ixx
FILE_SET cxx_modules TYPE CXX_MODULES FILES
${CMAKE_CURRENT_SOURCE_DIR}/Cell/Core.cpp
)

target_include_directories(CellCore PUBLIC ${GENERATED_INCLUDE_DIR})

add_dependencies(CellCore generate_headers)

add_executable(cell_app main.cpp)

target_link_libraries(cell_app PRIVATE CellCore)

add_dependencies(cell_app generate_headers)
11 changes: 11 additions & 0 deletions cell_framework/Cell/Core.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module;
#include <iostream>

module Cell.Core;

namespace Cell {
void Engine::run() {
std::cout << "Cell Engine running!" << std::endl;
std::cout << "2 + 2 = " << add(2, 2) << std::endl;
}
}
14 changes: 14 additions & 0 deletions cell_framework/Cell/Core.ixx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export module Cell.Core;

export import <vector>;

export namespace Cell {
inline int add(int a, int b) {
return a + b;
}

class Engine {
public:
void run();
};
}
27 changes: 27 additions & 0 deletions cell_framework/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Cell Framework Example with C++23 Modules

This example demonstrates the Cell framework using a modules-first design.
The build system uses CMake 3.26+ with the experimental C++ module API and
automatically generates traditional headers from module interface files.

## Prerequisites

- CMake 3.26 or newer
- A C++23 compiler with module support (Clang 18+ or equivalent)

## Building

```bash
mkdir build && cd build
cmake ..
cmake --build .
./cell_app
```

CMake should be invoked from a separate `build` directory to keep
generated files isolated from the source tree.

During configuration, module interfaces located in the `Cell/` directory are
converted into headers under `build/include/Cell`. These generated headers
allow interoperability with code that still relies on the traditional `#include`
mechanism.
7 changes: 7 additions & 0 deletions cell_framework/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Cell.Core;

int main() {
Cell::Engine engine;
engine.run();
return 0;
}
10 changes: 10 additions & 0 deletions scripts/generate_headers.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Simple header generation from module interface files
file(GLOB MODULE_FILES "${CMAKE_CURRENT_LIST_DIR}/../cell_framework/Cell/*.ixx")
foreach(MFILE ${MODULE_FILES})
get_filename_component(MNAME ${MFILE} NAME_WE)
set(HEADER "${GENERATED_INCLUDE_DIR}/Cell/${MNAME}.hpp")
file(MAKE_DIRECTORY "${GENERATED_INCLUDE_DIR}/Cell")
file(READ ${MFILE} CONTENTS)
string(REGEX REPLACE "export module ([A-Za-z0-9_.]+);" "#pragma once\n// Generated from module \1" CONTENTS "${CONTENTS}")
file(WRITE ${HEADER} "${CONTENTS}")
endforeach()
13 changes: 13 additions & 0 deletions scripts/install_zig.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env bash
set -euo pipefail
VERSION=0.14.1
URL="https://ziglang.org/download/${VERSION}/zig-$(uname -m)-linux-${VERSION}.tar.xz"
TMP_DIR=$(mktemp -d)
trap 'rm -rf "$TMP_DIR"' EXIT
curl -L "$URL" -o "$TMP_DIR/zig.tar.xz"
mkdir -p "$TMP_DIR/extract"
tar -xf "$TMP_DIR/zig.tar.xz" -C "$TMP_DIR/extract"
sudo rm -rf /usr/local/zig
sudo mkdir -p /usr/local/zig
sudo cp -r "$TMP_DIR/extract"/*/ /usr/local/zig/
sudo ln -sf /usr/local/zig/zig /usr/local/bin/zig
1 change: 1 addition & 0 deletions src/agent.zig
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ pub const personas = [_]Persona{

fn findPersona(name: []const u8) ?Persona {
for (personas) |p| {
if (std.mem.eqlIgnoreCase(u8, p.name, name)) return p;
if (std.mem.eql(u8, p.name, name)) return p;
}
return null;
Expand Down
13 changes: 7 additions & 6 deletions src/discord/gateway.zig
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,12 @@ fn handleTextFrame(self: *DiscordBot, payload: []const u8) !void {

const root = &parsed.value;
const opv = root.object.get("op") orelse return;
const op = @intCast(types.OpCode, opv.integer);
const op: types.OpCode = @enumFromInt(opv.integer);

switch (op) {
.hello => if (root.object.get("d")) |data| {
const interval = data.object.get("heartbeat_interval")?.integer orelse return;
const iv = data.object.get("heartbeat_interval") orelse return;
const interval = iv.integer;
try heartbeatLoop(self, @as(u32, @intCast(interval)));
try identify(self);
} else {},
Expand All @@ -55,7 +56,7 @@ fn heartbeatLoop(self: *DiscordBot, interval: u32) !void {
var ws = self.ws.?;
const buf = try self.allocator.alloc(u8, 32);
defer self.allocator.free(buf);
var timer = std.time.Timer.start() catch return;
_ = std.time.Timer.start() catch return;
while (true) {
try std.json.stringify(.{ .op = @as(u8, @intCast(types.OpCode.heartbeat)), .d = null }, .{}, std.io.fixedBufferStream(buf).writer());
try ws.writeFrame(.{ .fin = true, .opcode = .text, .data = buf });
Expand All @@ -65,10 +66,10 @@ fn heartbeatLoop(self: *DiscordBot, interval: u32) !void {

fn identify(self: *DiscordBot) !void {
var ws = self.ws.?;
const identify = types.Identify{ .token = self.token, .intents = 1 << 15 };
const id_payload = types.Identify{ .token = self.token, .intents = 1 << 15 };
var buf = std.ArrayList(u8).init(self.allocator);
defer buf.deinit();
try std.json.stringify(.{ .op = @as(u8, @intCast(types.OpCode.identify)), .d = identify }, .{}, buf.writer());
try std.json.stringify(.{ .op = @as(u8, @intCast(types.OpCode.identify)), .d = id_payload }, .{}, buf.writer());
try ws.writeFrame(.{ .fin = true, .opcode = .text, .data = buf.items });
}

Expand All @@ -79,7 +80,7 @@ fn fetchGatewayUrl(allocator: std.mem.Allocator, token: []const u8) ![]const u8
const auth_value = try std.fmt.allocPrint(allocator, "Bot {s}", .{token});
defer allocator.free(auth_value);

const headers = [_]std.http.Header{ .{ .name = "Authorization", .value = auth_value } };
const headers = [_]std.http.Header{.{ .name = "Authorization", .value = auth_value }};
var buf = std.ArrayList(u8).init(allocator);
defer buf.deinit();
const result = try client.fetch(.{ .location = .{ .url = "https://discord.com/api/v10/gateway" }, .extra_headers = &headers, .response_storage = .dynamic(&buf) });
Expand Down
2 changes: 1 addition & 1 deletion src/discord/types.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub const OpCode = enum(u8) {
identify = 2,
presence_update = 3,
voice_state_update = 4,
resume = 6,
resume_session = 6,
reconnect = 7,
request_guild_members = 8,
invalid_session = 9,
Expand Down
27 changes: 27 additions & 0 deletions src/engine/graphics.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const std = @import("std");

pub const GraphicsBackend = enum {
vulkan,
metal,
direct3d12,
opengl,
webgpu,
};

pub const GraphicsDriver = struct {
backend: GraphicsBackend,

pub fn init(backend: GraphicsBackend) GraphicsDriver {
return GraphicsDriver{ .backend = backend };
}

pub fn renderFrame(self: *GraphicsDriver) void {
// cross-platform rendering placeholder
_ = self;
}
};

test "GraphicsDriver init" {
const driver = GraphicsDriver.init(.vulkan);
try std.testing.expect(driver.backend == .vulkan);
}
1 change: 1 addition & 0 deletions src/engine/mod.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub const graphics = @import("graphics.zig");
4 changes: 2 additions & 2 deletions src/localml.zig
Original file line number Diff line number Diff line change
Expand Up @@ -211,9 +211,9 @@ pub fn main() !void {
const data_contents = try std.fs.cwd().readFileAlloc(alloc, data_path, 1024 * 1024);
defer alloc.free(data_contents);

var lines = std.mem.tokenize(u8, data_contents, "\n");
var lines = std.mem.tokenizeScalar(u8, data_contents, '\n');
while (lines.next()) |line| {
var cols = std.mem.tokenize(u8, line, ",");
var cols = std.mem.tokenizeScalar(u8, line, ',');
const x1 = try std.fmt.parseFloat(f64, cols.next() orelse continue);
const x2 = try std.fmt.parseFloat(f64, cols.next() orelse continue);
const label = try std.fmt.parseFloat(f64, cols.next() orelse continue);
Expand Down
31 changes: 5 additions & 26 deletions src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const gpu = @import("../zvim/gpu_renderer.zig");
const simd = @import("../zvim/simd_text.zig");
const lockfree = @import("lockfree.zig");
const platform = @import("platform.zig");
const engine = @import("engine/mod.zig");

pub const Error = error{
EmptyText,
Expand Down Expand Up @@ -91,37 +92,15 @@ pub const Abi = struct {
pub fn main() !void {
var args = std.process.args();
_ = args.next(); // exe name
var driver = engine.graphics.GraphicsDriver.init(.opengl);
driver.renderFrame();
if (args.next()) |arg| {
if (std.mem.eql(u8, arg, "tui")) {
const tui = @import("tui.zig");
try tui.run();
return;
} else if (std.mem.eql(u8, arg, "discord")) {
const api = @import("discord/api.zig");
const gw = @import("discord/gateway.zig");
const bot = @import("discord_bot.zig");
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();

const token = std.process.getEnvVarOwned(allocator, "DISCORD_TOKEN") catch {
std.log.err("DISCORD_TOKEN environment variable not set", .{});
return;
};
defer allocator.free(token);

const channel = args.next() orelse {
std.log.err("channel id required", .{});
return;
};

var bot = gw.DiscordBot.init(allocator, token);
defer bot.deinit();
// Non-blocking send using REST API
try api.postMessage(allocator, token, channel, "Hello from Zig!");
// Connect to gateway in blocking mode (example only)
// try bot.connect();
try bot.postMessage(allocator, token, channel, "Hello from Zig!");
std.log.err("discord feature not available", .{});
return;
}
}
Expand All @@ -130,7 +109,7 @@ pub fn main() !void {
.text = "example input",
.values = &[_]usize{ 1, 2, 3, 4 },
};
const res = Abi.process(req);
const res = try Abi.process(req);
const stdout = std.io.getStdOut().writer();
try stdout.print("{s}: {d}\n", .{ res.message, res.result });
}
Expand Down
Loading
Loading