-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPackage.swift
More file actions
347 lines (328 loc) · 17.2 KB
/
Copy pathPackage.swift
File metadata and controls
347 lines (328 loc) · 17.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
// swift-tools-version: 6.0
//
// NeuralCompose — Privacy-first macOS BCI communication prototype.
//
// Module layout (MLX isolation is load-bearing):
//
// NeuralComposeApp (executable, SwiftUI)
// │
// ├── BCICore pure-Swift models, protocols, buffers, intent FSM
// ├── BCIEEG BrainFlow facade + synthetic + playback streams
// ├── BCIClassifier Core ML wrapper (ANE-preferred) + mock classifier
// └── BCILLM MLX-Swift adapter + stub predictor + tokenizer
//
// MLX-Swift and swift-transformers are linked ONLY into BCILLM.
// The app target talks to BCILLM through the `NextWordPredicting` protocol from
// BCICore, so there is exactly one MLX runtime copy in the linked binary.
//
// BrainFlow is intentionally NOT a SwiftPM dependency. It is an optional system
// library, surfaced through the BCIBridge C++/Obj-C++ shim and gated by the
// `BCI_BRAINFLOW_AVAILABLE` compile flag. Without it, BCIEEG transparently
// falls back to the synthetic stream so the app builds and runs out-of-the-box.
import PackageDescription
let package = Package(
name: "NeuralCompose",
platforms: [
.macOS(.v14)
],
products: [
.executable(name: "NeuralCompose", targets: ["NeuralComposeApp"]),
.library(name: "BCICore", targets: ["BCICore"]),
.library(name: "BCIEEG", targets: ["BCIEEG"]),
.library(name: "BCIClassifier", targets: ["BCIClassifier"]),
.library(name: "BCILLM", targets: ["BCILLM"]),
.library(name: "BCIVoice", targets: ["BCIVoice"]),
.library(name: "BCICloudBridge", targets: ["BCICloudBridge"]),
.library(name: "WorldModelDemo", targets: ["WorldModelDemo"]),
.executable(name: "EmbeddingBench", targets: ["EmbeddingBench"]),
.executable(name: "SemanticEval", targets: ["SemanticEval"]),
.executable(name: "MLXProbe", targets: ["MLXProbe"]),
.executable(name: "SpectralProbe", targets: ["SpectralProbe"]),
.executable(name: "GenerationEval", targets: ["GenerationEval"]),
.executable(name: "dialectic-smoke", targets: ["DialecticSmoke"]),
.executable(name: "dialectic-session", targets: ["DialecticSession"]),
],
dependencies: [
// MLX runtime + small-model utilities. Pinned conservatively; bump as
// upstream releases stabilize. BCILLM is the *only* target that
// imports any of these products.
.package(url: "https://github.com/ml-explore/mlx-swift", from: "0.21.2"),
.package(url: "https://github.com/ml-explore/mlx-swift-examples", from: "2.21.0"),
// Tokenizer + chat-template utilities. Used strictly offline.
.package(url: "https://github.com/huggingface/swift-transformers", from: "0.1.20"),
],
targets: [
// ── C++/Obj-C++ bridge ────────────────────────────────────────────
.target(
name: "BCIBridge",
path: "Sources/BCIBridge",
publicHeadersPath: "include",
cxxSettings: [
.headerSearchPath("include"),
// Default to stub mode. Define BCI_BRAINFLOW_AVAILABLE at
// build time (and provide -lBrainflow / header path) to wire
// in a real BrainFlow installation.
.define("BCI_BRIDGE_STUB"),
]
),
// ── Core abstractions, no third-party deps ────────────────────────
.target(
name: "BCICore",
path: "Sources/BCICore",
swiftSettings: strictConcurrency
),
// ── EEG streaming ────────────────────────────────────────────────
.target(
name: "BCIEEG",
dependencies: ["BCICore", "BCIBridge"],
path: "Sources/BCIEEG",
swiftSettings: strictConcurrency
),
// ── Core ML intent classifier ────────────────────────────────────
.target(
name: "BCIClassifier",
dependencies: ["BCICore"],
path: "Sources/BCIClassifier",
swiftSettings: strictConcurrency
),
// ── MLX LLM (isolated) ───────────────────────────────────────────
.target(
name: "BCILLM",
dependencies: [
"BCICore",
.product(name: "MLX", package: "mlx-swift"),
.product(name: "MLXNN", package: "mlx-swift"),
.product(name: "MLXRandom", package: "mlx-swift"),
.product(name: "MLXLLM", package: "mlx-swift-examples"),
.product(name: "MLXLMCommon", package: "mlx-swift-examples"),
// Sentence-embedding models (BERT family) for the Stage 3.4
// RQ1 MLXSentenceEmbedder — mlx_lm cannot load encoders.
.product(name: "MLXEmbedders", package: "mlx-swift-examples"),
.product(name: "Transformers", package: "swift-transformers"),
],
path: "Sources/BCILLM",
swiftSettings: strictConcurrency + [
.define("BCI_HAS_MLX")
]
),
// ── Push-to-talk dictation + TTS (system frameworks only) ─────────
.target(
name: "BCIVoice",
dependencies: ["BCICore"],
path: "Sources/BCIVoice",
swiftSettings: strictConcurrency,
linkerSettings: [.linkedFramework("Speech")]
),
// ── Cloud bridge (the ONE deliberate network-egress module) ──────
// Quarantines the sole runtime exception to the "No network at
// runtime" invariant (decision_registry.md entry 8): the opt-in
// Stage-5 hypnagogic loop's cloud LLM. Kept OUT of BCILLM on purpose —
// the boundary contract names Sources/BCILLM/ as off-limits for cloud
// models — and depends only on BCICore (the TextGenerating seam), with
// no MLX/AVFoundation. Egress is via the local `claude` CLI subprocess
// (Foundation.Process); no HTTP client, no API key on disk. Imported
// only by NeuralComposeApp; must never become a dependency of any other
// BCI* target.
.target(
name: "BCICloudBridge",
dependencies: ["BCICore"],
path: "Sources/BCICloudBridge",
swiftSettings: strictConcurrency
),
// ── World Model demo (synthetic-task JEPA+MPC, CoreML/ANE) ────────
// Deliberately NOT a `BCI*`-prefixed name: every `BCI*` target is a
// real production-pipeline stage; this is a synthetic-task research
// demo (see WorldModel/README.md), never fed real EEG. Depends only
// on BCICore — no MLX, no new third-party deps. Imported only by
// NeuralComposeApp; must never become a dependency of any BCI*
// target.
.target(
name: "WorldModelDemo",
dependencies: ["BCICore"],
path: "Sources/WorldModelDemo",
swiftSettings: strictConcurrency
),
// ── Application ──────────────────────────────────────────────────
.executableTarget(
name: "NeuralComposeApp",
dependencies: ["BCICore", "BCIEEG", "BCIBridge", "BCIClassifier", "BCILLM", "BCIVoice", "BCICloudBridge", "WorldModelDemo"],
path: "Sources/NeuralComposeApp",
// Info.plist lives in Resources/ for reference / Xcode builds but
// is intentionally NOT declared as a SwiftPM resource: SwiftPM
// forbids Info.plist as a top-level resource. `swift run` produces
// a runnable binary without one.
exclude: ["Resources/Info.plist"],
swiftSettings: strictConcurrency
),
// ── Embedding benchmark harness (Stage 3.1) ───────────────────────
// Sibling executable, not a test target and not part of the app.
// Depends only on BCICore so it can measure any `SentenceEmbedder`
// conformer — including a future CoreMLSentenceEmbedder or
// MLXSentenceEmbedder — without this target ever importing CoreML
// or MLX itself. See docs/architecture/embedding_contract.md §6.
.executableTarget(
name: "EmbeddingBench",
// BCIClassifier is needed to construct CoreMLSentenceEmbedder
// (Stage 3.2) directly by its concrete type; BCILLM likewise for
// MLXSentenceEmbedder (Stage 3.4 RQ1) — BenchmarkRunner itself
// stays generic over `any SentenceEmbedder` and knows nothing
// about Core ML or MLX. Single executable → still one MLX
// runtime in the linked binary.
dependencies: ["BCICore", "BCIClassifier", "BCILLM"],
path: "Sources/EmbeddingBench",
swiftSettings: strictConcurrency
),
// ── Semantic evaluation (Stage 3.3) ───────────────────────────────
// Sibling executable, generic over `any SentenceEmbedder` (a
// `--model` flag picks the concrete conformer — argument parsing,
// not a backend registry). Emits raw embeddings and cosine
// relationships only; projection and clustering metrics are
// derived downstream in Scripts/generate-semantic-eval-artifacts.py.
.executableTarget(
name: "SemanticEval",
dependencies: ["BCICore", "BCIClassifier"],
path: "Sources/SemanticEval",
swiftSettings: strictConcurrency
),
// ── MLX load probe (temporary diagnostic) ─────────────────────────
// Isolated `MLXNextWordPredictor.init()` + `generate()` call with
// none of `PredictorFactory`'s subprocess/semaphore/App-lifecycle
// machinery around it. See Sources/MLXProbe/main.swift's doc
// comment. Delete this target once the probe-subprocess stall is
// diagnosed.
.executableTarget(
name: "MLXProbe",
dependencies: ["BCILLM"],
path: "Sources/MLXProbe",
swiftSettings: strictConcurrency
),
// ── Spectral encoder load probe ────────────────────────────────────
// Same rationale as MLXProbe, kept as its own target rather than a
// `--kind` flag on MLXProbe: MLXProbe's own doc comment marks it as
// a temporary diagnostic slated for deletion once the probe-
// subprocess stall it was built to investigate is resolved, while
// spectral probing is permanent infrastructure for
// SpectralStateEstimatorFactory's stub-by-default fallback. See
// Sources/SpectralProbe/main.swift's doc comment.
.executableTarget(
name: "SpectralProbe",
dependencies: ["BCILLM"],
path: "Sources/SpectralProbe",
swiftSettings: strictConcurrency
),
// ── Generation evaluation harness ──────────────────────────────────
// Sibling executable, same shape as EmbeddingBench/SemanticEval:
// runs several MLX text-generation candidates (Evaluation/corpora/
// generation_eval_candidates_v1.json) against a shared prompt corpus
// (generation_eval_prompts_v1.json), emitting raw evidence
// (Evaluation/<date>-generation-eval/data.json) plus a
// scoring-template.csv for the dimensions that don't have a
// reliable automatic score. BCIClassifier is only for the optional
// CoreMLSentenceEmbedder meaning-preservation scorer, same reason
// EmbeddingBench/SemanticEval depend on it.
.executableTarget(
name: "GenerationEval",
dependencies: ["BCILLM", "BCICore", "BCIClassifier"],
path: "Sources/GenerationEval",
swiftSettings: strictConcurrency
),
// ── Sonnet-5 runtime smoke (co-dev loop, Phase 1) ─────────────────
// Sibling executable that drives the real ClaudeCLIGenerator +
// waking role prompts end-to-end, with no EEG/GUI, to prove the
// Sonnet-5 runtime agent is reachable before a live session. Depends
// only on BCICore (the roles/prompts) + BCICloudBridge (the sole
// network-egress module) — no MLX, so it builds under CLT.
.executableTarget(
name: "DialecticSmoke",
dependencies: ["BCICore", "BCICloudBridge"],
path: "Sources/DialecticSmoke",
swiftSettings: strictConcurrency
),
// Headless scripted runner of the FULL dialectic loop (real Sonnet calls +
// the reflective Witness) — the seed-002 Focused-vs-Reflective experiment.
// Same dep shape as DialecticSmoke (no MLX; builds under CLT).
.executableTarget(
name: "DialecticSession",
dependencies: ["BCICore", "BCICloudBridge"],
path: "Sources/DialecticSession",
swiftSettings: strictConcurrency
),
// ── Tests ────────────────────────────────────────────────────────
.testTarget(
name: "BCICoreTests",
// BCIClassifier is pulled in for SemanticBGEReplayRegressionTests,
// which exercises the same text -> SentenceEmbedder -> Embedding ->
// RandomProjectionProjector pipeline as the stub's replay test, but
// against CoreMLSentenceEmbedder (BCIClassifier). Same rationale as
// BCIEEGTests pulling in BCIClassifier below: a dedicated
// cross-module test target felt like overkill for one suite.
dependencies: ["BCICore", "BCIClassifier"],
path: "Tests/BCICoreTests"
),
.testTarget(
name: "BCIEEGTests",
// BCIClassifier is pulled in for GoldenRecordingRegressionTests,
// which exercises the full playback -> windowing -> features ->
// classifier pipeline against a real recording. A dedicated
// cross-module test target felt like overkill for one suite.
dependencies: ["BCIEEG", "BCICore", "BCIClassifier"],
path: "Tests/BCIEEGTests",
// Fixtures/reference_pipeline.json is read directly by file path
// (relative to #filePath) rather than through Bundle.module, so
// it doesn't need SwiftPM resource bundling — just excluded so
// the build doesn't warn about an unhandled file.
exclude: ["Fixtures/reference_pipeline.json"]
),
.testTarget(
name: "BCIClassifierTests",
dependencies: ["BCIClassifier", "BCICore"],
path: "Tests/BCIClassifierTests"
),
.testTarget(
name: "BCILLMTests",
// MLX itself (not just BCILLM) is needed directly:
// SpectralEncoderModelTests constructs a raw MLXArray to drive
// SpectralEncoderModel's shape/unit-norm invariants against
// random-init weights — no model file on disk, so it runs
// under plain `swift test` (MLX kernels only fault on eval()).
dependencies: [
"BCILLM", "BCICore",
.product(name: "MLX", package: "mlx-swift"),
],
path: "Tests/BCILLMTests"
),
.testTarget(
name: "BCIVoiceTests",
dependencies: ["BCIVoice", "BCICore"],
path: "Tests/BCIVoiceTests"
),
.testTarget(
name: "BCICloudBridgeTests",
dependencies: ["BCICloudBridge", "BCICore"],
path: "Tests/BCICloudBridgeTests"
),
.testTarget(
name: "WorldModelDemoTests",
dependencies: ["WorldModelDemo", "BCICore"],
path: "Tests/WorldModelDemoTests"
),
.testTarget(
name: "NeuralComposeAppTests",
dependencies: ["NeuralComposeApp", "BCICore", "BCIEEG", "BCIClassifier", "BCILLM", "BCIVoice"],
path: "Tests/NeuralComposeAppTests"
),
],
cxxLanguageStandard: .cxx17
)
// MARK: - Shared Swift settings
var strictConcurrency: [SwiftSetting] {
[
.enableExperimentalFeature("StrictConcurrency"),
.enableUpcomingFeature("ExistentialAny"),
// Not enabling InternalImportsByDefault — it forces every public
// signature touching Foundation types (UUID, URL, Data) to either
// re-export Foundation or wrap them. The friction isn't worth it
// for an executable + four internal libraries that always link
// together.
]
}