Skip to content

Latest commit

 

History

History
338 lines (270 loc) · 10.7 KB

File metadata and controls

338 lines (270 loc) · 10.7 KB

API Reference

LocalScript exposes two HTTP services. This document is the complete API contract for both.

Service Base URL (default) Port
llm-service http://localhost:8080 8080
sandbox-service http://localhost:6778 6778

llm-service: GET /health

Returns service status and the active session count.

curl -s http://localhost:8080/health

Response 200:

{
  "status": "ok",
  "active_sessions": 2,
  "pipeline_model": "qwen2.5-coder:7b"
}
Field Type Description
status string Always "ok" when the process is up.
active_sessions integer Number of in-memory sessions currently tracked.
pipeline_model string The configured GENERATION_MODEL.

llm-service: POST /generate

Creates a new generation session or continues an existing one. This is the primary API.

Request

{
  "session_id": "string (optional)",
  "task": "string",
  "user_response": "string (optional)",
  "llm_validation": true
}
Field Type Default Description
session_id string | null null Omit on the first call. Reuse the returned value to continue a session.
task string "" The natural-language task. Required for a new session. May include inline workflow-context JSON (see Task Context).
user_response string "" The user's answer to the current state: approval or revision feedback.
llm_validation boolean true When false, skips the LLM critic step (sandbox validation still runs).

Errors:

Status Condition
400 task is missing/empty and no existing session_id was provided.
500 The session is in an unexpected state.

Response

{
  "session_id": "string",
  "state": "string",
  "plan": "string | null",
  "code": "string | null",
  "sandbox_feedback": "string | null",
  "message": "string"
}
Field Type Description
session_id string The session identifier; reuse it in the next request.
state string One of the session states.
plan string | null The generated plan (present when a plan was produced).
code string | null The generated/revised Lua code (present when code exists).
sandbox_feedback string | null Validation/critique feedback when the code did not pass, null otherwise.
message string Human-readable guidance for the next step (currently in Russian).

Session states

State Meaning
generating_plan Plan generation in progress (transient).
awaiting_plan_confirmation Plan ready — send an approval word or revision feedback.
generating_code Code generation + validation in progress (transient).
awaiting_code_approval Code ready and validated — send approval or revision feedback.
done Code approved. The response returns the final code.

Approval words

  • Plan approval (case-insensitive): подтвердить, да, согласен, утверждаю, approve, confirm, yes, ok, хорошо, принять, ок (plus demo aliases 78, 67, docker, борзячка). Any other value is treated as revision feedback.
  • Code approval (case-insensitive): only подтвердить. Any other value triggers a code revision.

Task Context (JSON)

The task field may embed a JSON object describing workflow state. llm-service extracts the JSON, strips it from the task text, normalizes it to the {"wf": {...}} shape, and injects it into the sandbox as the global wf table.

Example task:

Clean the values of variables ID, ENTITY_ID, CALL

{"wf": {"vars": {"RESTbody": {"result": [{"ID": 123}]}}, "initVariables": {}}}

Within generated Lua code, the data is available as:

  • wf.vars.<name> — mutable workflow variables.
  • wf.initVariables.<name> — read-only input parameters.

sandbox-service: GET /health

curl -s http://localhost:6778/health

Response 200: plain text ok.


sandbox-service: POST /pipeline

Validates (and optionally executes) a Lua snippet. This is the endpoint llm-service uses internally, but it can be called directly for testing or integration.

Request

{
  "code": "string",
  "execute": true,
  "timeout": 2,
  "context": {
    "wf": {
      "vars": {},
      "initVariables": {}
    }
  }
}
Field Type Default Description
code string — (required) The Lua source code to validate.
execute boolean false If true, run the code in the runtime sandbox. If false, only static checks are performed.
timeout integer 2 Execution timeout in seconds, clamped to [1, 10].
context object | null null Injected as the global wf table (wf.vars, wf.initVariables). Defaults to empty wf if omitted.

Response

{
  "status": "ok",
  "source_code": "string",
  "output": "string | null",
  "logs": ["string"],
  "warnings": ["string"],
  "error_detail": { "kind": "string", "message": "string", "line": 2, "raw": "string", "snippet": "string | null" } | null,
  "ast_analysis": {
    "function_calls": ["string"],
    "has_dangerous_patterns": false,
    "has_forbidden_calls": false
  } | null,
  "execution_stats": {
    "memory_used_bytes": 12345,
    "execution_time_ms": 2
  } | null
}
Field Type Description
status string ok, syntax_error, safety_error, runtime_error, or timeout.
source_code string Echo of the submitted code.
output string | null Values returned by the script (only when execute is true and execution succeeds).
logs string[] Sandbox log lines ([stdout], [warn], [exec], [error], [fatal]).
warnings string[] Non-fatal notices (e.g., timeout normalization, execution skipped).
error_detail object | null Structured error; null on success.
ast_analysis object | null Extracted function calls and safety flags; present when parsing succeeded.
execution_stats object | null Memory used and execution time; present when execution ran.

error_detail kinds

Kind Meaning
syntax_error Code could not be parsed.
safety_error Dangerous text pattern or forbidden call detected.
runtime_error Lua runtime error.
timeout Execution exceeded the configured timeout.
memory_limit Execution exceeded the 8 MB memory limit.
stack_overflow Lua C-stack overflow.
forbidden_access Attempted to access a disabled global (os, io, …).
unknown Unclassified error.

error_detail.line and error_detail.snippet point at the offending location; the snippet highlights the error line with >>>.

Example responses

Successful execution:

{
  "status": "ok",
  "source_code": "return 1 + 1",
  "output": "2",
  "logs": [
    "[exec] starting, timeout=2s",
    "[exec] code: 12 bytes",
    "[exec] memory used: 4096 bytes"
  ],
  "warnings": [],
  "error_detail": null,
  "ast_analysis": {
    "function_calls": [],
    "has_dangerous_patterns": false,
    "has_forbidden_calls": false
  },
  "execution_stats": {
    "memory_used_bytes": 4096,
    "execution_time_ms": 1
  }
}

Forbidden call:

{
  "status": "safety_error",
  "source_code": "os.execute('rm -rf /')",
  "output": null,
  "logs": [],
  "warnings": [],
  "error_detail": {
    "kind": "safety_error",
    "message": "dangerous text pattern found: rm -rf, forbidden function call found: os.execute",
    "line": null,
    "raw": "dangerous text pattern found: rm -rf, forbidden function call found: os.execute",
    "snippet": null
  },
  "ast_analysis": {
    "function_calls": ["os.execute"],
    "has_dangerous_patterns": true,
    "has_forbidden_calls": true
  },
  "execution_stats": null
}

Worked Example

A full session via llm-service, from new task to final approval.

Step 1 — create session, get a plan:

curl -sS -X POST http://localhost:8080/generate \
  -H "Content-Type: application/json" \
  -d '{"task":"Write a Lua function that filters a table of orders by total >= 100"}'
{
  "session_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "state": "awaiting_plan_confirmation",
  "plan": "$: Define the input handling\n$: Filter items where total >= 100\n$: Return the filtered table",
  "code": null,
  "sandbox_feedback": null,
  "message": "План сгенерирован. Подтвердите или укажите исправления."
}

Step 2 — request a plan revision (optional):

curl -sS -X POST http://localhost:8080/generate \
  -H "Content-Type: application/json" \
  -d '{"session_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","user_response":"Also compute the sum of filtered totals"}'

Step 3 — approve the plan, receive validated code:

curl -sS -X POST http://localhost:8080/generate \
  -H "Content-Type: application/json" \
  -d '{"session_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","user_response":"approve"}'
{
  "session_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "state": "awaiting_code_approval",
  "plan": null,
  "code": "local filtered = {}\nfor _, order in ipairs(wf.vars.orders or {}) do\n  if order.total >= 100 then\n    table.insert(filtered, order)\n  end\nend\nreturn filtered",
  "sandbox_feedback": null,
  "message": "Код прошёл проверки. Подтвердите или укажите исправления."
}

Step 4 — approve the code, session completes:

curl -sS -X POST http://localhost:8080/generate \
  -H "Content-Type: application/json" \
  -d '{"session_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","user_response":"подтвердить"}'
{
  "session_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "state": "done",
  "plan": null,
  "code": "local filtered = {}\nfor _, order in ipairs(wf.vars.orders or {}) do\n  if order.total >= 100 then\n    table.insert(filtered, order)\n  end\nend\nreturn filtered",
  "sandbox_feedback": null,
  "message": "Код одобрен. Генерация завершена."
}

Because LLM output is non-deterministic, the actual plan/code text will differ. The shape of the responses is what matters.