Cialtion commited on
Commit
945db12
Β·
verified Β·
1 Parent(s): bf21589

Update simpletool-game.skill.md

Browse files
Files changed (1) hide show
  1. simpletool-game.skill.md +318 -0
simpletool-game.skill.md ADDED
@@ -0,0 +1,318 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SimpleTool Skill β€” Real-Time AI Application Development
2
+
3
+ > **This is a skill file.** Feed it to any AI coding assistant (Claude, Gemini, GPT, Cursor, etc.) as context, then describe the app you want. The AI will generate a working SimpleTool-powered application.
4
+ >
5
+ > Example prompt: *"Read the attached SimpleTool skill, then build me a Pong game where AI controls one paddle in real-time."*
6
+
7
+ ---
8
+
9
+ ## 1. What is SimpleTool?
10
+
11
+ SimpleTool is a **multi-head parallel decoding** server for real-time LLM function calling. It runs on vLLM and decodes function name + arguments simultaneously instead of sequentially.
12
+
13
+ ```
14
+ Traditional: function β†’ arg1 β†’ arg2 β†’ ... (sequential, ~200-500ms)
15
+ SimpleTool: [function, arg1, arg2, ...] (parallel, ~25-60ms)
16
+ ```
17
+
18
+ **Application domains**: game AI, robotic arm control, digital human animation, IoT automation β€” anything that needs < 100ms LLM decision-making.
19
+
20
+ ## 2. Server API
21
+
22
+ Server default: `http://localhost:8899`
23
+
24
+ ### Endpoints
25
+ | Method | Path | Description |
26
+ |--------|------|-------------|
27
+ | GET | `/health` | Health check, returns `{status, version, model}` |
28
+ | POST | `/v1/function_call` | Multi-head parallel function call |
29
+
30
+ ### Request Format (v2)
31
+ ```javascript
32
+ {
33
+ messages: [{role: 'user', content: 'your query'}],
34
+ tools: [...], // OpenAI-format tool definitions
35
+ system: "domain prompt", // Domain-specific system prompt (v2)
36
+ environment: [...], // Current state info (string array, optional)
37
+ history: [...], // Action history (string array, max 6)
38
+ include_content_head: false // Whether to generate <content> head
39
+ }
40
+ ```
41
+
42
+ The `system` field lets you inject a domain-specific system prompt (e.g., "You are a robotic arm controller"). If omitted, the server uses a generic default. The `environment` field is optional context folded into the user message.
43
+
44
+ ### Response Format
45
+ ```javascript
46
+ {
47
+ success: true,
48
+ function: "move",
49
+ args: {direction: "up", speed: "fast"}, // Named args (param names from tool def)
50
+ heads: { // Raw per-head output
51
+ function: "move",
52
+ arg1: "up",
53
+ arg2: "fast",
54
+ arg3: "<|null|>"
55
+ },
56
+ content: null, // Only if include_content_head was true
57
+ latency_ms: 35.2
58
+ }
59
+ ```
60
+
61
+ ## 3. Dynamic Head Count (Critical for Latency!)
62
+
63
+ **The server automatically prunes unused heads.** If your tools have at most 2 parameters, only 3 heads are spawned (`<function>`, `<arg1>`, `<arg2>`), not 8. This saves ~40% latency.
64
+
65
+ ```
66
+ Active heads = [<function>] + [<arg1>...<argN>]
67
+ where N = max parameter count across all tool definitions
68
+ ```
69
+
70
+ **Design tip**: Keep your tools to 1–3 parameters when possible. Fewer params = fewer heads = lower latency.
71
+
72
+ ## 4. Tool Definition
73
+
74
+ ### Constraints
75
+ - Maximum **6 arguments** per function (arg1–arg6)
76
+ - Arguments map to `arg1, arg2, ...` in the order defined in `properties`
77
+ - Server auto-converts types: numeric strings β†’ int/float, otherwise lowercase string
78
+ - Use `enum` to constrain options β€” this dramatically improves accuracy
79
+
80
+ ### Template
81
+ ```javascript
82
+ const TOOLS = [{
83
+ type: "function",
84
+ function: {
85
+ name: "action_name",
86
+ description: "Clear, concise β€” what this action does and when to use it",
87
+ parameters: {
88
+ type: "object",
89
+ properties: {
90
+ param1: {
91
+ type: "string",
92
+ enum: ["opt_a", "opt_b", "opt_c"], // Constrain! Improves accuracy
93
+ description: "What this param controls"
94
+ },
95
+ param2: {
96
+ type: "number",
97
+ description: "Numeric value with unit, e.g. 'Force in Newtons'"
98
+ }
99
+ },
100
+ required: ["param1"]
101
+ }
102
+ }
103
+ }];
104
+ ```
105
+
106
+ ### Multi-Tool Example (Game)
107
+ ```javascript
108
+ const TOOLS = [
109
+ {type:"function", function:{name:"move", description:"Move unit to position", parameters:{type:"object", properties:{unit:{type:"string"}, target:{type:"string", enum:["north","south","east","west"]}}}}},
110
+ {type:"function", function:{name:"attack", description:"Attack enemy", parameters:{type:"object", properties:{unit:{type:"string"}, target:{type:"string"}}}}},
111
+ {type:"function", function:{name:"retreat", description:"Pull back unit", parameters:{type:"object", properties:{unit:{type:"string"}}}}},
112
+ {type:"function", function:{name:"pass", description:"Do nothing this turn", parameters:{type:"object", properties:{}}}}
113
+ ];
114
+ // Max params = 2 β†’ only 3 heads spawned
115
+ ```
116
+
117
+ ## 5. Query Design
118
+
119
+ ### Principles
120
+ 1. **Be imperative** β€” tell the model what to decide, not just describe state
121
+ 2. **Include decision context** β€” "Ball is BELOW paddle, intercept it" not "Ball y=250"
122
+ 3. **List valid options** β€” "Choose: up/down/stay"
123
+ 4. **Keep it short** β€” shorter query = faster prefill
124
+
125
+ ### Good vs Bad
126
+ ```
127
+ βœ… "Ball 50px BELOW paddle, approaching fast. Move DOWN to intercept. Choose: up/down/stay"
128
+ ❌ "Ball position: 250, Paddle position: 200. What should I do?"
129
+
130
+ βœ… "Red gear at (300,150,50). Move arm there slowly for pickup."
131
+ ❌ "There is a gear somewhere on the table. The arm needs to go to it."
132
+
133
+ βœ… "Stream starting, viewers saying hello. Greet them warmly."
134
+ ❌ "Viewers are in the chat. Do something appropriate."
135
+ ```
136
+
137
+ ### Environment & History
138
+ ```javascript
139
+ // Environment: current state as key=value strings
140
+ const env = [
141
+ `ball_y=${ballY}`,
142
+ `paddle_y=${paddleY}`,
143
+ `gap=${gap}`,
144
+ `approaching=true`
145
+ ];
146
+
147
+ // History: recent actions (max 6, server trims automatically)
148
+ const history = [
149
+ "move(up)", "move(up)", "stay()"
150
+ ];
151
+ ```
152
+
153
+ ### Domain System Prompts (v2)
154
+ For v2 server, set a domain-specific system prompt:
155
+ ```javascript
156
+ // Game AI
157
+ const SYSTEM = "You are the AI controller for a Pong game. Move the paddle to intercept the ball. React quickly.";
158
+
159
+ // Robotic arm
160
+ const SYSTEM = "You are the voice controller for a 6-axis robotic arm. Convert commands to precise function calls. Coordinates in mm.";
161
+
162
+ // Digital human
163
+ const SYSTEM = "You are the animation controller for a virtual streamer. Convert director instructions to expression and speech calls.";
164
+ ```
165
+
166
+ ## 6. Frontend Code Standards
167
+
168
+ ### Required: Type-Safe Value Extraction
169
+ ```javascript
170
+ // Values in args may be int, not string β€” always coerce
171
+ function safeStr(v) {
172
+ if (v === null || v === undefined) return '';
173
+ return String(v).trim().toLowerCase();
174
+ }
175
+
176
+ // Extract with args (named) first, heads (positional) as fallback
177
+ let direction = safeStr(d.args?.direction) || safeStr(d.heads?.arg1);
178
+ ```
179
+
180
+ ### Required: Validate Return Values
181
+ ```javascript
182
+ const VALID = ['up', 'down', 'stay'];
183
+ if (!VALID.includes(direction)) {
184
+ console.warn(`Invalid: "${direction}", fallback to stay`);
185
+ direction = 'stay';
186
+ }
187
+ ```
188
+
189
+ ### Required: Error Handling with Fallback
190
+ ```javascript
191
+ async function callAI() {
192
+ try {
193
+ const r = await fetch(SERVER_URL + '/v1/function_call', {
194
+ method: 'POST',
195
+ headers: {'Content-Type': 'application/json'},
196
+ body: JSON.stringify(request)
197
+ });
198
+ const data = await r.json();
199
+ if (!data.success) throw new Error(data.error);
200
+ applyAction(data);
201
+ } catch (e) {
202
+ console.error('[AI] Failed:', e);
203
+ applyFallbackAI(); // MUST have fallback β€” never freeze the app
204
+ }
205
+ }
206
+ ```
207
+
208
+ ### Required: Logging
209
+ ```javascript
210
+ console.log(`[Game] Query: ${query}`);
211
+ console.log(`[Game] β†’ ${data.function}(${JSON.stringify(data.args)}) ${data.latency_ms.toFixed(0)}ms`);
212
+ ```
213
+
214
+ ### Recommended: Debug UI Overlay
215
+ Show in a corner of your app: current query, raw response, latency (current + rolling average).
216
+
217
+ ## 7. Game Loop Pattern
218
+
219
+ **Decouple AI from rendering.** The AI loop runs at 10–16 Hz; the render loop runs at 60 fps.
220
+
221
+ ```javascript
222
+ const AI_INTERVAL = 100; // 100ms = 10 Hz
223
+ let aiPending = false;
224
+
225
+ // Render loop (60fps) β€” never blocks on AI
226
+ function gameLoop() {
227
+ update();
228
+ render();
229
+ requestAnimationFrame(gameLoop);
230
+ }
231
+
232
+ // AI loop (async, non-blocking)
233
+ async function aiLoop() {
234
+ if (aiPending) return;
235
+ aiPending = true;
236
+ await callAI();
237
+ aiPending = false;
238
+ }
239
+
240
+ setInterval(aiLoop, AI_INTERVAL);
241
+ gameLoop();
242
+ ```
243
+
244
+ ## 8. FCClient Template
245
+
246
+ Drop-in client class for any HTML/JS application:
247
+
248
+ ```javascript
249
+ class FCClient {
250
+ constructor(url = 'http://localhost:8899') {
251
+ this.url = url.replace(/\/$/, '');
252
+ }
253
+
254
+ async health() {
255
+ try {
256
+ const r = await fetch(`${this.url}/health`, {signal: AbortSignal.timeout(3000)});
257
+ const d = await r.json();
258
+ return {ok: d.loaded === true || d.status === 'ok', version: d.version};
259
+ } catch (e) {
260
+ return {ok: false};
261
+ }
262
+ }
263
+
264
+ async call({query, tools, system, env, history, includeContent = false}) {
265
+ const t0 = performance.now();
266
+ try {
267
+ const r = await fetch(`${this.url}/v1/function_call`, {
268
+ method: 'POST',
269
+ headers: {'Content-Type': 'application/json'},
270
+ body: JSON.stringify({
271
+ messages: [{role: 'user', content: query}],
272
+ tools,
273
+ system, // v2: domain system prompt
274
+ environment: env,
275
+ history,
276
+ include_content_head: includeContent
277
+ })
278
+ });
279
+ const d = await r.json();
280
+ return {...d, wall_ms: performance.now() - t0};
281
+ } catch (e) {
282
+ return {success: false, error: e.message, wall_ms: performance.now() - t0};
283
+ }
284
+ }
285
+ }
286
+ ```
287
+
288
+ Usage:
289
+ ```javascript
290
+ const ai = new FCClient('http://localhost:8899');
291
+
292
+ const result = await ai.call({
293
+ query: "Ball is BELOW. Move down. Choose: up/down/stay",
294
+ tools: TOOLS,
295
+ system: "You are a Pong AI. Move paddle to intercept ball.",
296
+ env: ["ball_y=300", "paddle_y=200", "gap=100"],
297
+ history: ["move(down)", "move(down)"]
298
+ });
299
+
300
+ if (result.success) {
301
+ console.log(`${result.function}(${JSON.stringify(result.args)}) in ${result.latency_ms}ms`);
302
+ }
303
+ ```
304
+
305
+ ## 9. Troubleshooting
306
+
307
+ | Symptom | Cause | Fix |
308
+ |---------|-------|-----|
309
+ | AI stuck / no movement | Query too vague | Add decision hints: "Move DOWN to intercept" |
310
+ | `.trim is not a function` | `args` values may be int | Use `String(v)` before `.trim()` |
311
+ | High latency (>100ms) | Too many heads / long query | Reduce tool params, shorten query/env |
312
+ | Wrong function called | Ambiguous tool descriptions | Add `enum`, improve `description` fields |
313
+ | `<|null|>` in all args | Model confused | Check tool param order matches expectations |
314
+
315
+ ---
316
+
317
+ **Skill Version**: 2.0 β€” Supports v1/v2 server, multi-domain (game, robotics, avatar)
318
+ **Last Updated**: 2026-03