@ebowwa/logic-spec 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +125 -0
- package/REFERENCE.md +147 -0
- package/SPEC.md +783 -0
- package/dist/cli.js +6713 -0
- package/dist/index.js +6663 -0
- package/examples/minimal.yaml +49 -0
- package/examples/smart-glass-supervisor.yaml +330 -0
- package/examples/state-machine.yaml +106 -0
- package/package.json +50 -0
- package/schema.json +409 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# logic.yaml - Minimal Example
|
|
2
|
+
# Simple data transformation
|
|
3
|
+
|
|
4
|
+
meta:
|
|
5
|
+
spec_version: "1.0"
|
|
6
|
+
name: string-reverser
|
|
7
|
+
version: "1.0.0"
|
|
8
|
+
description: Reverses input strings
|
|
9
|
+
|
|
10
|
+
inputs:
|
|
11
|
+
- name: text
|
|
12
|
+
type: string
|
|
13
|
+
required: true
|
|
14
|
+
description: The string to reverse
|
|
15
|
+
|
|
16
|
+
outputs:
|
|
17
|
+
- name: reversed
|
|
18
|
+
type: string
|
|
19
|
+
description: The reversed string
|
|
20
|
+
|
|
21
|
+
logic:
|
|
22
|
+
- id: reverse
|
|
23
|
+
type: transform
|
|
24
|
+
input: text
|
|
25
|
+
output: reversed
|
|
26
|
+
algorithm: |
|
|
27
|
+
1. Take input string
|
|
28
|
+
2. Reverse character order
|
|
29
|
+
3. Return reversed string
|
|
30
|
+
complexity: O(n)
|
|
31
|
+
|
|
32
|
+
tests:
|
|
33
|
+
- name: basic_reverse
|
|
34
|
+
given:
|
|
35
|
+
text: "hello"
|
|
36
|
+
expect:
|
|
37
|
+
reversed: "olleh"
|
|
38
|
+
|
|
39
|
+
- name: empty_string
|
|
40
|
+
given:
|
|
41
|
+
text: ""
|
|
42
|
+
expect:
|
|
43
|
+
reversed: ""
|
|
44
|
+
|
|
45
|
+
- name: single_char
|
|
46
|
+
given:
|
|
47
|
+
text: "a"
|
|
48
|
+
expect:
|
|
49
|
+
reversed: "a"
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
# logic.yaml - Smart Glass Supervisor
|
|
2
|
+
# Real-time visual analysis for smart glasses
|
|
3
|
+
|
|
4
|
+
meta:
|
|
5
|
+
spec_version: "1.0"
|
|
6
|
+
name: smart-glass-supervisor
|
|
7
|
+
version: "1.0.0"
|
|
8
|
+
description: Real-time visual segmentation and AI analysis
|
|
9
|
+
language_target: any
|
|
10
|
+
|
|
11
|
+
inputs:
|
|
12
|
+
- name: camera_stream
|
|
13
|
+
type: MediaStream
|
|
14
|
+
required: true
|
|
15
|
+
schema:
|
|
16
|
+
frames_per_second: 30
|
|
17
|
+
resolution: [1280, 720]
|
|
18
|
+
format: video/webm
|
|
19
|
+
|
|
20
|
+
- name: user_query
|
|
21
|
+
type: string
|
|
22
|
+
required: false
|
|
23
|
+
default: null
|
|
24
|
+
description: Optional voice/text query from user
|
|
25
|
+
|
|
26
|
+
- name: settings
|
|
27
|
+
type: Settings
|
|
28
|
+
required: false
|
|
29
|
+
default:
|
|
30
|
+
overlay_enabled: true
|
|
31
|
+
segmentation_enabled: true
|
|
32
|
+
language: en
|
|
33
|
+
|
|
34
|
+
outputs:
|
|
35
|
+
- name: analysis_result
|
|
36
|
+
type: AnalysisResult
|
|
37
|
+
description: Real-time analysis output
|
|
38
|
+
|
|
39
|
+
- name: composite_stream
|
|
40
|
+
type: MediaStream
|
|
41
|
+
description: Video stream with overlay
|
|
42
|
+
|
|
43
|
+
types:
|
|
44
|
+
MediaStream:
|
|
45
|
+
fields:
|
|
46
|
+
frames_per_second: number
|
|
47
|
+
resolution: array
|
|
48
|
+
format: string
|
|
49
|
+
|
|
50
|
+
Settings:
|
|
51
|
+
fields:
|
|
52
|
+
overlay_enabled: boolean
|
|
53
|
+
segmentation_enabled: boolean
|
|
54
|
+
language: string
|
|
55
|
+
|
|
56
|
+
Frame:
|
|
57
|
+
fields:
|
|
58
|
+
data: string
|
|
59
|
+
timestamp: number
|
|
60
|
+
width: number
|
|
61
|
+
height: number
|
|
62
|
+
|
|
63
|
+
Segment:
|
|
64
|
+
fields:
|
|
65
|
+
label: string
|
|
66
|
+
bbox: BoundingBox
|
|
67
|
+
confidence: number
|
|
68
|
+
color: string
|
|
69
|
+
|
|
70
|
+
BoundingBox:
|
|
71
|
+
fields:
|
|
72
|
+
x: number
|
|
73
|
+
y: number
|
|
74
|
+
width: number
|
|
75
|
+
height: number
|
|
76
|
+
|
|
77
|
+
AnalysisResult:
|
|
78
|
+
fields:
|
|
79
|
+
text_response: string
|
|
80
|
+
segments: array
|
|
81
|
+
timestamp: number
|
|
82
|
+
confidence: number
|
|
83
|
+
processing_time_ms: number
|
|
84
|
+
|
|
85
|
+
InferenceError:
|
|
86
|
+
enum: [TIMEOUT, RATE_LIMITED, MODEL_ERROR, INVALID_INPUT]
|
|
87
|
+
|
|
88
|
+
logic:
|
|
89
|
+
- id: capture_frame
|
|
90
|
+
type: transform
|
|
91
|
+
input: camera_stream
|
|
92
|
+
output: frame
|
|
93
|
+
algorithm: |
|
|
94
|
+
1. Extract current frame from video stream
|
|
95
|
+
2. Encode as base64/jpeg
|
|
96
|
+
3. Attach timestamp
|
|
97
|
+
4. Return Frame object
|
|
98
|
+
complexity: O(1)
|
|
99
|
+
|
|
100
|
+
- id: build_prompt
|
|
101
|
+
type: transform
|
|
102
|
+
input: [frame, user_query, settings]
|
|
103
|
+
output: prompt
|
|
104
|
+
algorithm: |
|
|
105
|
+
1. Base prompt: "Analyze this image for a smart glasses user"
|
|
106
|
+
2. If user_query exists, append: "User asks: {query}"
|
|
107
|
+
3. If segmentation_enabled, append segmentation instructions
|
|
108
|
+
4. Return complete prompt string
|
|
109
|
+
|
|
110
|
+
- id: gemini_inference
|
|
111
|
+
type: inference
|
|
112
|
+
input: [frame, prompt]
|
|
113
|
+
output: raw_response
|
|
114
|
+
algorithm: |
|
|
115
|
+
1. Send frame + prompt to Gemini 2.0 Flash
|
|
116
|
+
2. Request structured response with segments
|
|
117
|
+
3. Parse JSON response
|
|
118
|
+
4. Return {text, segments, confidence}
|
|
119
|
+
|
|
120
|
+
- id: parse_segments
|
|
121
|
+
type: transform
|
|
122
|
+
input: raw_response
|
|
123
|
+
output: segments
|
|
124
|
+
algorithm: |
|
|
125
|
+
1. Extract segment array from response
|
|
126
|
+
2. Validate each segment has required fields
|
|
127
|
+
3. Normalize bounding box coordinates to frame dimensions
|
|
128
|
+
4. Assign colors based on segment labels
|
|
129
|
+
5. Return Segment[]
|
|
130
|
+
|
|
131
|
+
- id: render_overlay
|
|
132
|
+
type: transform
|
|
133
|
+
input: [frame, segments, settings]
|
|
134
|
+
output: overlay_canvas
|
|
135
|
+
algorithm: |
|
|
136
|
+
1. Create transparent canvas matching frame dimensions
|
|
137
|
+
2. For each segment:
|
|
138
|
+
a. Draw bounding box with segment color
|
|
139
|
+
b. Draw label text above box
|
|
140
|
+
c. Draw confidence percentage
|
|
141
|
+
3. Return canvas with overlay
|
|
142
|
+
|
|
143
|
+
- id: composite_streams
|
|
144
|
+
type: transform
|
|
145
|
+
input: [camera_stream, overlay_canvas]
|
|
146
|
+
output: composite_stream
|
|
147
|
+
algorithm: |
|
|
148
|
+
1. Layer overlay canvas on video stream
|
|
149
|
+
2. Maintain original frame rate
|
|
150
|
+
3. Apply alpha blending for overlay transparency
|
|
151
|
+
4. Return composite MediaStream
|
|
152
|
+
|
|
153
|
+
- id: format_result
|
|
154
|
+
type: aggregate
|
|
155
|
+
input: [raw_response, segments, processing_time]
|
|
156
|
+
output: analysis_result
|
|
157
|
+
algorithm: |
|
|
158
|
+
1. Combine text response from inference
|
|
159
|
+
2. Include parsed segments
|
|
160
|
+
3. Calculate overall confidence (average of segment confidences)
|
|
161
|
+
4. Attach processing time metric
|
|
162
|
+
5. Return AnalysisResult
|
|
163
|
+
|
|
164
|
+
state:
|
|
165
|
+
initial: idle
|
|
166
|
+
persist: false
|
|
167
|
+
states:
|
|
168
|
+
idle:
|
|
169
|
+
description: Camera not active
|
|
170
|
+
capturing:
|
|
171
|
+
description: Actively capturing frames
|
|
172
|
+
processing:
|
|
173
|
+
description: Frame sent to AI, awaiting response
|
|
174
|
+
displaying:
|
|
175
|
+
description: Showing analysis results
|
|
176
|
+
|
|
177
|
+
transitions:
|
|
178
|
+
- from: idle
|
|
179
|
+
to: capturing
|
|
180
|
+
trigger: camera_enabled
|
|
181
|
+
action: capture_frame
|
|
182
|
+
|
|
183
|
+
- from: capturing
|
|
184
|
+
to: processing
|
|
185
|
+
trigger: frame_ready
|
|
186
|
+
action: gemini_inference
|
|
187
|
+
|
|
188
|
+
- from: processing
|
|
189
|
+
to: displaying
|
|
190
|
+
trigger: inference_complete
|
|
191
|
+
action: [parse_segments, render_overlay, composite_streams]
|
|
192
|
+
|
|
193
|
+
- from: displaying
|
|
194
|
+
to: capturing
|
|
195
|
+
trigger: display_complete
|
|
196
|
+
|
|
197
|
+
- from: capturing
|
|
198
|
+
to: idle
|
|
199
|
+
trigger: camera_disabled
|
|
200
|
+
|
|
201
|
+
- from: processing
|
|
202
|
+
to: capturing
|
|
203
|
+
trigger: inference_error
|
|
204
|
+
|
|
205
|
+
flows:
|
|
206
|
+
- name: realtime_analysis
|
|
207
|
+
description: Full real-time analysis pipeline
|
|
208
|
+
steps:
|
|
209
|
+
- capture_frame
|
|
210
|
+
- build_prompt
|
|
211
|
+
- gemini_inference
|
|
212
|
+
- parse_segments
|
|
213
|
+
- render_overlay
|
|
214
|
+
- composite_streams
|
|
215
|
+
- format_result
|
|
216
|
+
parallel: false
|
|
217
|
+
timeout_ms: 500
|
|
218
|
+
|
|
219
|
+
- name: frame_only
|
|
220
|
+
description: Capture without AI analysis
|
|
221
|
+
steps:
|
|
222
|
+
- capture_frame
|
|
223
|
+
timeout_ms: 33
|
|
224
|
+
|
|
225
|
+
failures:
|
|
226
|
+
- code: E001
|
|
227
|
+
condition: "camera_stream.unavailable"
|
|
228
|
+
severity: critical
|
|
229
|
+
recovery:
|
|
230
|
+
strategy: escalate
|
|
231
|
+
message: Camera stream not available
|
|
232
|
+
|
|
233
|
+
- code: E002
|
|
234
|
+
condition: "gemini_inference.timeout > 30000ms"
|
|
235
|
+
severity: error
|
|
236
|
+
recovery:
|
|
237
|
+
strategy: retry
|
|
238
|
+
retry_count: 2
|
|
239
|
+
message: AI inference timed out
|
|
240
|
+
|
|
241
|
+
- code: E003
|
|
242
|
+
condition: "gemini_inference.rate_limited"
|
|
243
|
+
severity: warning
|
|
244
|
+
recovery:
|
|
245
|
+
strategy: fallback
|
|
246
|
+
fallback_to: cached_response
|
|
247
|
+
message: API rate limit exceeded
|
|
248
|
+
|
|
249
|
+
- code: E004
|
|
250
|
+
condition: "memory_usage > 256MB"
|
|
251
|
+
severity: warning
|
|
252
|
+
recovery:
|
|
253
|
+
strategy: ignore
|
|
254
|
+
message: High memory usage detected
|
|
255
|
+
|
|
256
|
+
constraints:
|
|
257
|
+
latency_max_ms: 500
|
|
258
|
+
frame_drop_tolerance: 0.05
|
|
259
|
+
memory_limit_mb: 256
|
|
260
|
+
throughput_min_rps: 30
|
|
261
|
+
|
|
262
|
+
dependencies:
|
|
263
|
+
- name: gemini_api
|
|
264
|
+
type: external_service
|
|
265
|
+
contract: VisionAPI
|
|
266
|
+
required: true
|
|
267
|
+
timeout_ms: 30000
|
|
268
|
+
auth: api_key
|
|
269
|
+
|
|
270
|
+
- name: camera_hardware
|
|
271
|
+
type: hardware
|
|
272
|
+
contract: CameraDevice
|
|
273
|
+
required: true
|
|
274
|
+
|
|
275
|
+
observability:
|
|
276
|
+
metrics:
|
|
277
|
+
- name: frame_capture_rate
|
|
278
|
+
type: gauge
|
|
279
|
+
unit: fps
|
|
280
|
+
- name: inference_latency_ms
|
|
281
|
+
type: histogram
|
|
282
|
+
unit: ms
|
|
283
|
+
labels: [model, success]
|
|
284
|
+
- name: segment_count
|
|
285
|
+
type: gauge
|
|
286
|
+
- name: frame_drops_total
|
|
287
|
+
type: counter
|
|
288
|
+
|
|
289
|
+
logs:
|
|
290
|
+
level: info
|
|
291
|
+
include: [frame_timestamp, query, segment_count, latency_ms]
|
|
292
|
+
exclude: [frame_data, raw_response]
|
|
293
|
+
|
|
294
|
+
traces:
|
|
295
|
+
enabled: true
|
|
296
|
+
sample_rate: 0.1
|
|
297
|
+
|
|
298
|
+
tests:
|
|
299
|
+
- name: happy_path_with_query
|
|
300
|
+
given:
|
|
301
|
+
camera_stream: valid_stream
|
|
302
|
+
user_query: "What objects are in front of me?"
|
|
303
|
+
settings: {overlay_enabled: true, segmentation_enabled: true}
|
|
304
|
+
expect:
|
|
305
|
+
analysis_result.text_response: "!null"
|
|
306
|
+
analysis_result.segments: "type:array"
|
|
307
|
+
analysis_result.confidence: ">= 0.5"
|
|
308
|
+
|
|
309
|
+
- name: happy_path_no_query
|
|
310
|
+
given:
|
|
311
|
+
camera_stream: valid_stream
|
|
312
|
+
user_query: null
|
|
313
|
+
expect:
|
|
314
|
+
analysis_result.text_response: "!null"
|
|
315
|
+
analysis_result.segments: "type:array"
|
|
316
|
+
|
|
317
|
+
- name: segmentation_disabled
|
|
318
|
+
given:
|
|
319
|
+
camera_stream: valid_stream
|
|
320
|
+
settings: {overlay_enabled: true, segmentation_enabled: false}
|
|
321
|
+
expect:
|
|
322
|
+
analysis_result.segments: []
|
|
323
|
+
|
|
324
|
+
- name: inference_timeout
|
|
325
|
+
given:
|
|
326
|
+
camera_stream: slow_stream
|
|
327
|
+
when: realtime_analysis
|
|
328
|
+
expect:
|
|
329
|
+
analysis_result: "!null"
|
|
330
|
+
timeout_ms: 60000
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# logic.yaml - State Machine Example
|
|
2
|
+
# Traffic light controller
|
|
3
|
+
|
|
4
|
+
meta:
|
|
5
|
+
spec_version: "1.0"
|
|
6
|
+
name: traffic-light
|
|
7
|
+
version: "1.0.0"
|
|
8
|
+
description: Traffic light state machine with timing
|
|
9
|
+
|
|
10
|
+
inputs:
|
|
11
|
+
- name: event
|
|
12
|
+
type: Event
|
|
13
|
+
required: true
|
|
14
|
+
schema:
|
|
15
|
+
type: timer_expired | emergency_override | reset
|
|
16
|
+
|
|
17
|
+
outputs:
|
|
18
|
+
- name: light_state
|
|
19
|
+
type: LightState
|
|
20
|
+
schema:
|
|
21
|
+
current: string
|
|
22
|
+
duration_ms: number
|
|
23
|
+
|
|
24
|
+
types:
|
|
25
|
+
Event:
|
|
26
|
+
enum: [timer_expired, emergency_override, reset]
|
|
27
|
+
|
|
28
|
+
LightState:
|
|
29
|
+
fields:
|
|
30
|
+
current: string
|
|
31
|
+
duration_ms: number
|
|
32
|
+
|
|
33
|
+
logic:
|
|
34
|
+
- id: determine_next_state
|
|
35
|
+
type: decision
|
|
36
|
+
input: [current_state, event]
|
|
37
|
+
output: next_state
|
|
38
|
+
algorithm: |
|
|
39
|
+
1. If event is emergency_override, return "red"
|
|
40
|
+
2. If event is reset, return "green"
|
|
41
|
+
3. Otherwise, follow normal cycle:
|
|
42
|
+
- green -> yellow
|
|
43
|
+
- yellow -> red
|
|
44
|
+
- red -> green
|
|
45
|
+
|
|
46
|
+
- id: calculate_duration
|
|
47
|
+
type: compute
|
|
48
|
+
input: next_state
|
|
49
|
+
output: duration_ms
|
|
50
|
+
algorithm: |
|
|
51
|
+
1. green: 30000ms (30 seconds)
|
|
52
|
+
2. yellow: 5000ms (5 seconds)
|
|
53
|
+
3. red: 25000ms (25 seconds)
|
|
54
|
+
|
|
55
|
+
state:
|
|
56
|
+
initial: red
|
|
57
|
+
persist: true
|
|
58
|
+
states:
|
|
59
|
+
green:
|
|
60
|
+
description: Vehicles may proceed
|
|
61
|
+
yellow:
|
|
62
|
+
description: Vehicles should prepare to stop
|
|
63
|
+
red:
|
|
64
|
+
description: Vehicles must stop
|
|
65
|
+
|
|
66
|
+
transitions:
|
|
67
|
+
- from: red
|
|
68
|
+
to: green
|
|
69
|
+
trigger: timer_expired
|
|
70
|
+
action: determine_next_state
|
|
71
|
+
|
|
72
|
+
- from: green
|
|
73
|
+
to: yellow
|
|
74
|
+
trigger: timer_expired
|
|
75
|
+
|
|
76
|
+
- from: yellow
|
|
77
|
+
to: red
|
|
78
|
+
trigger: timer_expired
|
|
79
|
+
|
|
80
|
+
- from: green
|
|
81
|
+
to: red
|
|
82
|
+
trigger: emergency_override
|
|
83
|
+
|
|
84
|
+
- from: yellow
|
|
85
|
+
to: red
|
|
86
|
+
trigger: emergency_override
|
|
87
|
+
|
|
88
|
+
constraints:
|
|
89
|
+
latency_max_ms: 100
|
|
90
|
+
availability_percent: 99.99
|
|
91
|
+
|
|
92
|
+
tests:
|
|
93
|
+
- name: normal_cycle
|
|
94
|
+
given:
|
|
95
|
+
current_state: red
|
|
96
|
+
event: timer_expired
|
|
97
|
+
expect:
|
|
98
|
+
light_state.current: green
|
|
99
|
+
light_state.duration_ms: 30000
|
|
100
|
+
|
|
101
|
+
- name: emergency
|
|
102
|
+
given:
|
|
103
|
+
current_state: green
|
|
104
|
+
event: emergency_override
|
|
105
|
+
expect:
|
|
106
|
+
light_state.current: red
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ebowwa/logic-spec",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Language-agnostic standard for extracting pure logic from implementations into logic.yaml",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"logic-validate": "./dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"schema.json",
|
|
14
|
+
"SPEC.md",
|
|
15
|
+
"REFERENCE.md",
|
|
16
|
+
"examples"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "bun build ./src/index.ts ./src/cli.ts --outdir ./dist",
|
|
20
|
+
"validate": "bun run src/cli.ts",
|
|
21
|
+
"test": "bun test",
|
|
22
|
+
"prepublishOnly": "bun run build"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"logic",
|
|
26
|
+
"specification",
|
|
27
|
+
"yaml",
|
|
28
|
+
"ai",
|
|
29
|
+
"agents",
|
|
30
|
+
"code-generation",
|
|
31
|
+
"documentation",
|
|
32
|
+
"schema"
|
|
33
|
+
],
|
|
34
|
+
"author": "ebowwa",
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "https://github.com/ebowwa/codespaces",
|
|
39
|
+
"directory": "cerebralvalley/032126/smart-glass-supervisor/docs/logic-spec"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"yaml": "^2.8.3"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/bun": "latest"
|
|
46
|
+
},
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public"
|
|
49
|
+
}
|
|
50
|
+
}
|