Two recipes for LLM-backed TCP services: a transparent AI proxy that any net-plugin client can connect to, and an event-driven webhook router.
Modules: net plugin · curl plugin · JSON · String · Konsol
Hosts a TCP session named ai-gateway on port 2310. Any connected player sends a plain-text prompt; the gateway forwards it to gpt-4o-mini and broadcasts the response back to all players. Runs forever until killed.
Key patterns:
Net:Host("gateway", 8, "ai-gateway", handle) - start the session; max 8 playersNet:Check(handle) every loop iteration - pumps the stack for connect/disconnect eventsNet:GetMessage drain loop - process all queued messages before the next CheckNet:Send(handle, reply, ok) - broadcast the LLM reply to every connected playerCurl:Post callsConnect with lan_chat.ks (choose j, session name ai-gateway) or any other net-plugin client.
Usage
# terminal 1 - start the gateway
minks ai_gateway.ks <openai_api_key>
# terminal 2 - connect as a player (uses lan_chat.ks from the web-and-network recipes)
minks lan_chat.ks
# > Host or join? j
# > Session: ai-gateway
# > Host IP: 127.0.0.1
Sample session
=== AI Gateway ===
Starting gateway session 'ai-gateway' on port 2310...
Ready. Waiting for players...
[alice] What is gradient descent?
[AI] Gradient descent is an optimization algorithm that iteratively adjusts...
[bob] How does it differ from stochastic gradient descent?
[AI] Stochastic gradient descent updates parameters using a single random sample...
Script
// ai_gateway.ks - TCP server that proxies player messages to an LLM
// Modules: net plugin, curl plugin, JSON, String, Konsol
// Usage: minks ai_gateway.ks <openai_api_key>
//
// Hosts a session named "ai-gateway" on port 2310. Any connected player can
// send a text prompt; the gateway forwards it to the LLM and broadcasts the
// response back to all players.
//
// Connect with lan_chat.ks (choose 'j', session = "ai-gateway") or any
// net-plugin client.
#include "net"
#include "curl"
Konsol:Print("=== AI Gateway ===");
// ── Step 1: Read the API key ──────────────────────────────────────────────────
Var:List args;
OS:Args(args);
Var:Number argc;
List:Size(args, argc);
if (argc < 1) {
Konsol:Print("Usage: minks ai_gateway.ks <openai_api_key>");
Konsol:Exit(1);
}
Var:String apiKey;
List:Get(0, args, apiKey);
// ── Step 2: Start the TCP session ────────────────────────────────────────────
// Net:Host registers this process as the host on port 2310.
// Players connect with Net:Join("ai-gateway", <host_ip>).
Konsol:Print("Starting gateway session 'ai-gateway' on port 2310...");
Var:Number handle;
Net:Host("gateway", 8, "ai-gateway", handle);
Konsol:Print("Ready. Waiting for players...");
// Set up curl headers once - they persist for all subsequent Curl:Post calls.
Curl:SetHeader("Authorization", "Bearer ${apiKey}");
Curl:SetHeader("Content-Type", "application/json");
Curl:SetTimeout(30);
// ── Step 3: Proxy loop ────────────────────────────────────────────────────────
// Net:Check pumps the network stack each iteration.
// Net:GetMessage drains one message at a time - loop until got = false.
Var:String sender;
Var:String msg;
Var:Boolean got;
Var:Boolean sendOk;
while (true) {
Net:Check(handle);
Net:GetMessage(handle, sender, msg, got);
while (got) {
Konsol:Print("[${sender}] ${msg}");
// Forward the player's message to the LLM.
Var:String safeMsg;
String:Replace(msg, "\"", "\\\"", safeMsg);
Var:String payload = """{
"model": "gpt-4o-mini",
"messages": [{"role": "user", "content": "${safeMsg}"}],
"max_tokens": 256
}""";
Var:String body;
Var:String reply;
try {
Curl:Post("https://api.openai.com/v1/chat/completions", payload, body);
Var:Number status;
Curl:Status(status);
if (status == 200) {
JSON:Parse(body, resp);
JSON:Get("choices.0.message.content", resp, reply);
String:Trim(reply, reply);
} else {
reply = "[gateway error: HTTP ${status}]";
}
} catch (CurlException e) {
reply = "[gateway error: ${e.message}]";
}
// Broadcast the LLM reply to all connected players.
Net:Send(handle, reply, sendOk);
Konsol:Print("[AI] ${reply}");
Net:GetMessage(handle, sender, msg, got);
}
}
Modules: net plugin · curl plugin · JSON · String · Dictionary · Konsol
Hosts a TCP session named webhooks on port 2310. Clients send JSON payloads; the receiver parses the event field, looks up an event-specific system prompt from a Dictionary, calls the LLM, and replies directly to the sender with Net:SendTo.
| Event | LLM task |
|---|---|
alert |
Root-cause analysis and remediation bullets |
question |
Direct Q&A answer |
summarize |
2–3 sentence summary of content field |
Key patterns:
Dictionary:New prompts + Dictionary:Set - route table; Dictionary:Has validates incoming event typeJSON:Parse(rawMsg, evt) + JSON:Get("event", ...) - parse the incoming payloadNet:SendTo(handle, sender, reply, ok) - targeted reply instead of broadcastPayload format (client sends)
{"event": "alert", "content": "CPU usage at 98% for 5 minutes on web-01"}
{"event": "question", "content": "What does P99 latency mean?"}
{"event": "summarize", "content": "The quarterly report shows a 12% increase in..."}
Usage
# terminal 1 - start the receiver
minks webhook_receiver.ks <openai_api_key>
# terminal 2 - send an event (any net-plugin client)
# payload is sent as a plain-text JSON string via Net:Send
Sample session
=== Webhook Receiver ===
Starting webhook session 'webhooks' on port 2310...
Ready. Waiting for events...
[monitor] {"event":"alert","content":"disk usage at 95% on /var/data"}
Routing 'alert' event to LLM...
→ [monitor] • Disk at 95% - immediate risk of write failures.
• Run `du -sh /*` to identify large directories.
• Archive or delete logs in /var/log and /var/data/tmp.
Script
// webhook_receiver.ks - receive JSON events over TCP and route to an LLM
// Modules: net plugin, curl plugin, JSON, String, Dictionary, Konsol
// Usage: minks webhook_receiver.ks <openai_api_key>
//
// Hosts a session named "webhooks" on port 2310. Senders deliver JSON
// payloads as plain text messages. The receiver parses the "event" field
// and routes the payload to the LLM with an event-specific system prompt.
//
// Supported event types and their LLM tasks:
// alert → root-cause analysis of the alert message
// question → direct Q&A answer
// summarize → concise summary of the "content" field
//
// Clients send with Net:Send; the gateway replies via Net:SendTo back to sender.
#include "net"
#include "curl"
Konsol:Print("=== Webhook Receiver ===");
// ── Step 1: Read the API key ──────────────────────────────────────────────────
Var:List args;
OS:Args(args);
Var:Number argc;
List:Size(args, argc);
if (argc < 1) {
Konsol:Print("Usage: minks webhook_receiver.ks <openai_api_key>");
Konsol:Exit(1);
}
Var:String apiKey;
List:Get(0, args, apiKey);
// ── Step 2: Build the event routing table ─────────────────────────────────────
// Each event type maps to a system prompt that shapes the LLM's response.
Dictionary:New prompts;
Dictionary:Set("alert", "You are a DevOps on-call assistant. Given an alert message, identify the likely cause and suggest immediate remediation steps in 2-3 bullet points.", prompts);
Dictionary:Set("question", "You are a helpful assistant. Answer the question clearly and concisely.", prompts);
Dictionary:Set("summarize", "You are a summarization assistant. Produce a concise 2-3 sentence summary of the provided content.", prompts);
// ── Step 3: Start the TCP session ────────────────────────────────────────────
Konsol:Print("Starting webhook session 'webhooks' on port 2310...");
Var:Number handle;
Net:Host("receiver", 16, "webhooks", handle);
Konsol:Print("Ready. Waiting for events...");
Curl:SetHeader("Authorization", "Bearer ${apiKey}");
Curl:SetHeader("Content-Type", "application/json");
Curl:SetTimeout(30);
// ── Step 4: Event loop ────────────────────────────────────────────────────────
Var:String sender;
Var:String rawMsg;
Var:Boolean got;
Var:Boolean sendOk;
while (true) {
Net:Check(handle);
Net:GetMessage(handle, sender, rawMsg, got);
while (got) {
Konsol:Print("[${sender}] ${rawMsg}");
// Parse the incoming JSON payload.
JSON:Parse(rawMsg, evt);
Var:String eventType;
Var:String payload;
JSON:Get("event", evt, eventType);
JSON:Get("content", evt, payload);
String:Trim(eventType, eventType);
// Look up the system prompt for this event type.
Var:Boolean hasPrompt;
Dictionary:Has(eventType, prompts, hasPrompt);
Var:String reply;
if (!hasPrompt) {
reply = "[unknown event type: ${eventType}]";
Konsol:Print(" Unknown event type '${eventType}' - ignored.");
} else {
Var:String sysMsg;
Dictionary:Get(eventType, prompts, sysMsg);
Konsol:Print(" Routing '${eventType}' event to LLM...");
// Build and send the request.
Var:String safePayload;
Var:String safeSys;
String:Replace(payload, "\"", "\\\"", safePayload);
String:Replace(sysMsg, "\"", "\\\"", safeSys);
Var:String apiPayload = """{
"model": "gpt-4o-mini",
"messages": [
{"role": "system", "content": "${safeSys}"},
{"role": "user", "content": "${safePayload}"}
],
"max_tokens": 300
}""";
Var:String body;
try {
Curl:Post("https://api.openai.com/v1/chat/completions", apiPayload, body);
Var:Number status;
Curl:Status(status);
if (status == 200) {
JSON:Parse(body, resp);
JSON:Get("choices.0.message.content", resp, reply);
String:Trim(reply, reply);
} else {
reply = "[LLM error: HTTP ${status}]";
}
} catch (CurlException e) {
reply = "[LLM error: ${e.message}]";
}
}
// Send the LLM reply back only to the original sender.
Net:SendTo(handle, sender, reply, sendOk);
Konsol:Print(" → [${sender}] ${reply}");
Net:GetMessage(handle, sender, rawMsg, got);
}
}