-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathProgram.fs
More file actions
600 lines (540 loc) · 28.1 KB
/
Copy pathProgram.fs
File metadata and controls
600 lines (540 loc) · 28.1 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
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
open System
open System.IO
open System.Net.Http
open System.Text
open System.Text.Json
open System.Text.Json.Serialization
open System.Diagnostics
open System.Collections.Generic
open System.Threading
open System.Text.RegularExpressions
open Microsoft.Data.Sqlite
// ============================================================
// 1. ТИПЫ ДАННЫХ И КОНФИГУРАЦИЯ
// ============================================================
type SemVer = {
[<JsonPropertyName("major")>] Major: int
[<JsonPropertyName("minor")>] Minor: int
[<JsonPropertyName("patch")>] Patch: int
}
type AgentResponse = {
[<JsonPropertyName("name")>] Name: string
[<JsonPropertyName("kind")>] Kind: string
[<JsonPropertyName("signature")>] Signature: string
[<JsonPropertyName("version")>] Version: SemVer
[<JsonPropertyName("source_code")>] SourceCode: string
[<JsonPropertyName("test_code")>] TestCode: string
[<JsonPropertyName("explanation")>] Explanation: string
[<JsonPropertyName("dependencies")>] Dependencies: string[]
}
type PlanResponse = {
[<JsonPropertyName("steps")>] Steps: string[]
}
type NamingResponse = {
[<JsonPropertyName("name")>] Name: string
}
type VersioningResponse = {
[<JsonPropertyName("version")>] Version: SemVer
[<JsonPropertyName("reason")>] Reason: string
}
type CoordinatorResponse = {
[<JsonPropertyName("action")>] Action: string
[<JsonPropertyName("step")>] Step: string
[<JsonPropertyName("reason")>] Reason: string
}
type DiagnosticsResponse = {
[<JsonPropertyName("suggestion")>] Suggestion: string
}
type DependencyResponse = {
[<JsonPropertyName("dependencies")>] Dependencies: string[]
}
type TypeDesignResponse = {
[<JsonPropertyName("type_declaration")>] TypeDeclaration: string
}
type Message = {
[<JsonPropertyName("role")>] Role: string
[<JsonPropertyName("content")>] Content: string
}
type ChatRequest = {
[<JsonPropertyName("model")>] Model: string
[<JsonPropertyName("messages")>] Messages: Message[]
[<JsonPropertyName("stream")>] Stream: bool
[<JsonPropertyName("format")>] Format: obj
}
module Config =
let jsonOptions =
let opts = JsonSerializerOptions(PropertyNamingPolicy = JsonNamingPolicy.CamelCase)
opts.PropertyNameCaseInsensitive <- true
opts
let httpClient = new HttpClient()
let ollamaUrl = "http://localhost:11434/api/chat"
let modelName = "qwen2.5-coder:latest"
let connectionString = "Data Source=gac_registry.db"
let codeFormatSchema = {|
``type`` = "object"
properties = {|
name = {| ``type`` = "string" |}
kind = {| ``type`` = "string"; enum = [| "type"; "function" |] |}
signature = {| ``type`` = "string" |}
version = {|
``type`` = "object"
properties = {|
major = {| ``type`` = "integer" |}
minor = {| ``type`` = "integer" |}
patch = {| ``type`` = "integer" |}
|}
required = [| "major"; "minor"; "patch" |]
|}
source_code = {| ``type`` = "string" |}
test_code = {| ``type`` = "string" |}
explanation = {| ``type`` = "string" |}
dependencies = {|
``type`` = "array"
items = {| ``type`` = "string" |}
|}
|}
required = [| "name"; "kind"; "signature"; "version"; "source_code"; "test_code"; "dependencies" |]
|}
let namingFormatSchema = {|
``type`` = "object"
properties = {|
name = {| ``type`` = "string"; description = "Базовое имя в camelCase без версий" |}
|}
required = [| "name" |]
|}
let versioningFormatSchema = {|
``type`` = "object"
properties = {|
version = {|
``type`` = "object"
properties = {|
major = {| ``type`` = "integer" |}
minor = {| ``type`` = "integer" |}
patch = {| ``type`` = "integer" |}
|}
required = [| "major"; "minor"; "patch" |]
|}
reason = {| ``type`` = "string" |}
|}
required = [| "version"; "reason" |]
|}
let coordinatorFormatSchema = {|
``type`` = "object"
properties = {|
action = {| ``type`` = "string"; enum = [| "next_step"; "done" |] |}
step = {| ``type`` = "string" |}
reason = {| ``type`` = "string" |}
|}
required = [| "action" |]
|}
let diagnosticsFormatSchema = {|
``type`` = "object"
properties = {|
suggestion = {| ``type`` = "string"; description = "Что конкретно исправить в коде" |}
|}
required = [| "suggestion" |]
|}
let dependencyFormatSchema = {|
``type`` = "object"
properties = {|
dependencies = {|
``type`` = "array"
items = {| ``type`` = "string" |}
|}
|}
required = [| "dependencies" |]
|}
let typeDesignFormatSchema = {|
``type`` = "object"
properties = {|
type_declaration = {| ``type`` = "string" |}
|}
required = [| "type_declaration" |]
|}
let systemPrompt = "Ты — автономный F#-разработчик. Пиши чистый, иммутабельный код без модулей и пространств имен. Применяй суффиксы версий к сущностям (напр. MyType_1_0_0)."
let namingPrompt = "Ты — эксперт по именованию в F#. Верни осмысленное базовое имя в camelCase БЕЗ суффиксов версий."
let versioningPrompt = "Ты — аудитор SemVer 2.0.0. Сравни задачу с реестром и рассчитай следующую версию."
let coordinatorPrompt = "Ты — координатор. Твоя задача — выдавать ТОЛЬКО конкретные шаги по созданию типов или функций. Каждый шаг должен начинаться со слов 'Создай тип...' или 'Создай функцию...'. Не выдавай аналитические или организационные шаги. Если все необходимые компоненты созданы, верни action='done'."
let diagnosticsPrompt = "Ты — эксперт-диагност. Изучи ошибку F# REPL и выдай одну лаконичную инструкцию, как исправить код."
let dependencyPrompt = "Ты — архитектор. Выбери из контекста реестра ТОЛЬКО те компоненты (ID с версиями), которые НЕПОСРЕДСТВЕННО необходимы для реализации нового компонента. Не выбирай лишние зависимости. Если зависимостей нет, верни пустой массив."
let typeDesignPrompt = "Ты — дизайнер типов F#. Спроектируй структуру (запись или DU) и верни её объявление с суффиксом версии."
// ============================================================
// 2. МОДУЛЬ ХРАНИЛИЩА (SQLite + Графовый Изолированный Обход)
// ============================================================
type DBRecord = {
Id: string
Name: string
Kind: string
Signature: string
Major: int
Minor: int
Patch: int
Source: string
Test: string
}
module DatabaseRegistry =
let initDatabase () =
use connection = new SqliteConnection(Config.connectionString)
connection.Open()
let createTablesSql = """
CREATE TABLE IF NOT EXISTS registry (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
kind TEXT NOT NULL,
signature TEXT NOT NULL,
version_major INTEGER NOT NULL,
version_minor INTEGER NOT NULL,
version_patch INTEGER NOT NULL,
source_code TEXT NOT NULL,
test_code TEXT,
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(name, version_major, version_minor, version_patch)
);
CREATE TABLE IF NOT EXISTS dependencies (
parent_id TEXT NOT NULL,
child_id TEXT NOT NULL,
PRIMARY KEY (parent_id, child_id),
FOREIGN KEY (parent_id) REFERENCES registry(id) ON DELETE CASCADE,
FOREIGN KEY (child_id) REFERENCES registry(id) ON DELETE CASCADE
);
"""
use cmd = new SqliteCommand(createTablesSql, connection)
cmd.ExecuteNonQuery() |> ignore
let saveComponent (node: AgentResponse) =
let safeString s = if isNull s then "" else s
let id = sprintf "%s_%d_%d_%d" (safeString node.Name) node.Version.Major node.Version.Minor node.Version.Patch
use connection = new SqliteConnection(Config.connectionString)
connection.Open()
use transaction = connection.BeginTransaction()
try
use cmd = new SqliteCommand(
"INSERT OR REPLACE INTO registry
(id, name, kind, signature, version_major, version_minor, version_patch, source_code, test_code, description)
VALUES (@id, @name, @kind, @signature, @major, @minor, @patch, @source, @test, @desc)",
connection, transaction)
cmd.Parameters.AddWithValue("@id", id) |> ignore
cmd.Parameters.AddWithValue("@name", safeString node.Name) |> ignore
cmd.Parameters.AddWithValue("@kind", safeString node.Kind) |> ignore
cmd.Parameters.AddWithValue("@signature", safeString node.Signature) |> ignore
cmd.Parameters.AddWithValue("@major", node.Version.Major) |> ignore
cmd.Parameters.AddWithValue("@minor", node.Version.Minor) |> ignore
cmd.Parameters.AddWithValue("@patch", node.Version.Patch) |> ignore
cmd.Parameters.AddWithValue("@source", safeString node.SourceCode) |> ignore
cmd.Parameters.AddWithValue("@test", safeString node.TestCode) |> ignore
cmd.Parameters.AddWithValue("@desc", safeString node.Explanation) |> ignore
cmd.ExecuteNonQuery() |> ignore
if node.Dependencies <> null then
for childId in node.Dependencies do
if not (String.IsNullOrWhiteSpace(childId)) then
use depCmd = new SqliteCommand(
"INSERT OR IGNORE INTO dependencies (parent_id, child_id) VALUES (@parent, @child)",
connection, transaction)
depCmd.Parameters.AddWithValue("@parent", id) |> ignore
depCmd.Parameters.AddWithValue("@child", childId) |> ignore
depCmd.ExecuteNonQuery() |> ignore
transaction.Commit()
printfn "[БД] Компонент %s сохранен." id
Some id
with ex ->
transaction.Rollback()
printfn "[БД Ошибка] %s" ex.Message
None
let private getChildrenIds id connection =
use cmd = new SqliteCommand("SELECT child_id FROM dependencies WHERE parent_id = @id", connection)
cmd.Parameters.AddWithValue("@id", id) |> ignore
use reader = cmd.ExecuteReader()
let list = new List<string>()
while reader.Read() do
list.Add(reader.GetString(0))
List.ofSeq list
let private getRecordById id connection =
use cmd = new SqliteCommand("SELECT id, name, kind, signature, version_major, version_minor, version_patch, source_code, test_code FROM registry WHERE id = @id", connection)
cmd.Parameters.AddWithValue("@id", id) |> ignore
use reader = cmd.ExecuteReader()
if reader.Read() then
Some {
Id = reader.GetString(0)
Name = reader.GetString(1)
Kind = reader.GetString(2)
Signature = reader.GetString(3)
Major = reader.GetInt32(4)
Minor = reader.GetInt32(5)
Patch = reader.GetInt32(6)
Source = reader.GetString(7)
Test = if reader.IsDBNull(8) then "" else reader.GetString(8)
}
else None
/// Лёгкий слепок только последних версий компонентов (id, kind, signature) для агентов
let getLatestRegistryMetadataOnly () : string =
use connection = new SqliteConnection(Config.connectionString)
connection.Open()
let sb = StringBuilder()
sb.AppendLine("// === ДОСТУПНЫЕ КОМПОНЕНТЫ (последние версии) ===") |> ignore
use cmd = new SqliteCommand("SELECT id, name, kind, signature FROM registry", connection)
use reader = cmd.ExecuteReader()
let allRecords =
[ while reader.Read() do
yield (reader.GetString(0), reader.GetString(1), reader.GetString(2), reader.GetString(3)) ]
let latest =
allRecords
|> List.groupBy (fun (_, name, _, _) -> name)
|> List.map (fun (name, lst) ->
let latestRec =
lst
|> List.maxBy (fun (id, _, _, _) ->
let parts = id.Split('_')
if parts.Length >= 4 then
(int parts.[parts.Length-3], int parts.[parts.Length-2], int parts.[parts.Length-1])
else (0,0,0))
latestRec)
for (id, _, kind, signature) in latest do
sb.AppendLine(sprintf "- ID: %s (%s) | Сигнатура: %s" id kind signature) |> ignore
sb.ToString()
/// Сборка изолированного графа зависимостей для REPL
let buildIsolatedExecutionContext (rootIds: string[]) : string =
let visited = HashSet<string>()
let sortedSourceCode = List<string>()
let sortedTestCode = List<string>()
use connection = new SqliteConnection(Config.connectionString)
connection.Open()
let rec dfs id =
if not (visited.Contains(id)) then
visited.Add(id) |> ignore
let children = getChildrenIds id connection
for childId in children do
dfs childId
match getRecordById id connection with
| Some record ->
sortedSourceCode.Add(record.Source)
if record.Kind = "function" && not (String.IsNullOrEmpty(record.Test)) then
sortedTestCode.Add(record.Test)
| None -> ()
for rootId in rootIds do
dfs rootId
let finalSources = String.concat "\n\n" sortedSourceCode
let finalTests = String.concat "\n\n" sortedTestCode
sprintf "%s\n\n// === ТЕСТЫ ЗАВИСИМОСТЕЙ ===\n%s" finalSources finalTests
// ============================================================
// 3. ЯДРО ВЗАИМОДЕЙСТВИЯ (Ollama API и FSI REPL)
// ============================================================
module CoreEngine =
let cleanJson (raw: string) =
let mutable s = raw.Trim()
if s.StartsWith("```json") then s <- s.Substring(7)
elif s.StartsWith("```") then s <- s.Substring(3)
if s.EndsWith("```") then s <- s.Substring(0, s.Length - 3)
s.Trim()
let queryOllama (messages: Message list) (schema: obj) : string option =
let requestPayload = {
Model = Config.modelName
Messages = List.toArray messages
Stream = false
Format = schema
}
let jsonStr = JsonSerializer.Serialize(requestPayload, Config.jsonOptions)
use content = new StringContent(jsonStr, Encoding.UTF8, "application/json")
try
use cts = new CancellationTokenSource(TimeSpan.FromSeconds(60.0))
let response = Config.httpClient.PostAsync(Config.ollamaUrl, content, cts.Token).GetAwaiter().GetResult()
if response.IsSuccessStatusCode then
let responseBody = response.Content.ReadAsStringAsync().GetAwaiter().GetResult()
use doc = JsonDocument.Parse(responseBody)
Some (cleanJson (doc.RootElement.GetProperty("message").GetProperty("content").GetString()))
else None
with _ -> None
let runInFsi (fsharpCode: string) : bool * string =
let prolog = "open System\n"
let fullExecutionScript = prolog + fsharpCode + "\n#q;;\n"
let startInfo = ProcessStartInfo(
FileName = "dotnet",
Arguments = "fsi --nologo --readline-",
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
)
use proc = new Process(StartInfo = startInfo)
proc.Start() |> ignore
let outputTask = proc.StandardOutput.ReadToEndAsync()
let errorTask = proc.StandardError.ReadToEndAsync()
use writer = proc.StandardInput
writer.Write(fullExecutionScript)
writer.Flush()
writer.Close()
if not (proc.WaitForExit(30_000)) then
try proc.Kill() with _ -> ()
false, "Таймаут выполнения скрипта в REPL (30 сек)."
else
outputTask.Wait(); errorTask.Wait()
let stdout = outputTask.Result
let stderr = errorTask.Result
let hasError =
stderr.Contains("error FS") ||
stderr.Contains("Assertion failed") ||
stdout.Contains("Assertion failed") ||
stdout.Contains("Сбой")
if hasError then false, sprintf "STDERR:\n%s\nSTDOUT:\n%s" stderr stdout
else true, stdout
// ============================================================
// 4. МНОГОАГЕНТСКАЯ ОРКЕСТРАЦИЯ
// ============================================================
module MultiAgentSystem =
let AskNaming task ctx =
let msgs = [
{ Role = "system"; Content = Config.namingPrompt }
{ Role = "user"; Content = sprintf "Задача: %s\nКонтекст:\n%s" task ctx }
]
match CoreEngine.queryOllama msgs Config.namingFormatSchema with
| Some j -> (JsonSerializer.Deserialize<NamingResponse>(j, Config.jsonOptions)).Name
| None -> "FallbackComponent"
let AskVersioning name task ctx =
let msgs = [
{ Role = "system"; Content = Config.versioningPrompt }
{ Role = "user"; Content = sprintf "Имя: %s\nЗадача: %s\nКонтекст:\n%s" name task ctx }
]
match CoreEngine.queryOllama msgs Config.versioningFormatSchema with
| Some j ->
let v = (JsonSerializer.Deserialize<VersioningResponse>(j, Config.jsonOptions)).Version
// Защита от нулевой версии
if v.Major = 0 && v.Minor = 0 && v.Patch = 0 then { Major = 1; Minor = 0; Patch = 0 } else v
| None -> { Major = 1; Minor = 0; Patch = 0 }
let AskDependencies task name (ver: SemVer) ctx =
let msgs = [
{ Role = "system"; Content = Config.dependencyPrompt }
{ Role = "user"; Content = sprintf "Задача: %s\nИмя: %s_%d_%d_%d\nКонтекст:\n%s" task name ver.Major ver.Minor ver.Patch ctx }
]
match CoreEngine.queryOllama msgs Config.dependencyFormatSchema with
| Some j -> (JsonSerializer.Deserialize<DependencyResponse>(j, Config.jsonOptions)).Dependencies
| None -> [||]
let AskTypeDesign task name (ver: SemVer) ctx =
let msgs = [
{ Role = "system"; Content = Config.typeDesignPrompt }
{ Role = "user"; Content = sprintf "Задача: %s\nИмя: %s_%d_%d_%d\nКонтекст:\n%s" task name ver.Major ver.Minor ver.Patch ctx }
]
match CoreEngine.queryOllama msgs Config.typeDesignFormatSchema with
| Some j -> Some (JsonSerializer.Deserialize<TypeDesignResponse>(j, Config.jsonOptions)).TypeDeclaration
| None -> None
let AskDiagnostics logs code ctx =
let msgs = [
{ Role = "system"; Content = Config.diagnosticsPrompt }
{ Role = "user"; Content = sprintf "Ошибка REPL:\n%s\nКод:\n%s\nКонтекст:\n%s" logs code ctx }
]
match CoreEngine.queryOllama msgs Config.diagnosticsFormatSchema with
| Some j -> (JsonSerializer.Deserialize<DiagnosticsResponse>(j, Config.jsonOptions)).Suggestion
| None -> "Исправь синтаксис F# кода."
let AskCoordinator task ctx history =
let hStr = if List.isEmpty history then "Нет выполненных шагов." else String.concat "\n- " history
let msgs = [
{ Role = "system"; Content = Config.coordinatorPrompt }
{ Role = "user"; Content = sprintf "Задача: %s\nРеестр:\n%s\nИстория:\n%s" task ctx hStr }
]
match CoreEngine.queryOllama msgs Config.coordinatorFormatSchema with
| Some j -> Some (JsonSerializer.Deserialize<CoordinatorResponse>(j, Config.jsonOptions))
| None -> None
// ============================================================
// 5. ИЗОЛИРОВАННЫЙ ЦИКЛ ЗАКРЫТОЙ КОРРЕКЦИИ
// ============================================================
let rec runClosedGenerationLoop
stepTask
(metaContext: string)
(isolatedCodeContext: string)
suggestedName
(version: SemVer)
deps
typeHint
suggestion
attempt =
if attempt >= 5 then
printfn "[Генератор] Достигнут предел попыток. Последняя ошибка: %s" suggestion
failwith "Не удалось сгенерировать рабочий кубик кода за 5 итераций REPL."
else
printfn "[Генератор] Попытка %d..." (attempt + 1)
let hintBlock =
match typeHint with
| Some t -> sprintf "\nИспользуй спроектированную структуру типа:\n%s" t
| None -> ""
let errorCorrectionBlock =
if String.IsNullOrEmpty(suggestion) then ""
else sprintf "\n\n[КРИТИЧЕСКАЯ ОШИБКА ПРОШЛОГО ЗАПУСКА REPL]\nИсправь согласно совету диагноста: %s" suggestion
let userPrompt =
sprintf
"Напиши компонент F#.\nИмя: %s\nВерсия: %d.%d.%d\nЗависимости: %s\nПодзадача: %s%s%s"
suggestedName version.Major version.Minor version.Patch (String.concat ", " deps) stepTask hintBlock errorCorrectionBlock
let messages = [
{ Role = "system"; Content = Config.systemPrompt }
{ Role = "user"; Content = userPrompt }
]
match CoreEngine.queryOllama messages Config.codeFormatSchema with
| None ->
runClosedGenerationLoop stepTask metaContext isolatedCodeContext suggestedName version deps typeHint "Ollama выдала пустой ответ." (attempt + 1)
| Some jsonStr ->
try
let response = JsonSerializer.Deserialize<AgentResponse>(jsonStr, Config.jsonOptions)
let verificationScript =
if response.Kind = "function" then
let verSuffix = sprintf "%d_%d_%d" version.Major version.Minor version.Patch
let testCall = sprintf "test_%s_%s()" suggestedName verSuffix
sprintf "%s\n\n%s\n\n%s\n\n%s" isolatedCodeContext response.SourceCode response.TestCode testCall
else
sprintf "%s\n\n%s" isolatedCodeContext response.SourceCode
let success, logs = CoreEngine.runInFsi verificationScript
if success then
{ response with Name = suggestedName; Version = version; Dependencies = deps }
else
printfn "[REPL Сбой] Логи ошибки:\n%s" logs
let nextSuggestion = MultiAgentSystem.AskDiagnostics logs response.SourceCode metaContext
runClosedGenerationLoop stepTask metaContext isolatedCodeContext suggestedName version deps typeHint nextSuggestion (attempt + 1)
with ex ->
runClosedGenerationLoop stepTask metaContext isolatedCodeContext suggestedName version deps typeHint (sprintf "Ошибка десериализации JSON: %s" ex.Message) (attempt + 1)
// ============================================================
// 6. ОРКЕСТРАЦИЯ КОМПОНЕНТОВ
// ============================================================
let runSingleWorkflowStep (stepTask: string) : bool =
let metaContext = DatabaseRegistry.getLatestRegistryMetadataOnly()
let name = MultiAgentSystem.AskNaming stepTask metaContext
let version = MultiAgentSystem.AskVersioning name stepTask metaContext
let dependencies = MultiAgentSystem.AskDependencies stepTask name version metaContext
let isolatedCodeContext = DatabaseRegistry.buildIsolatedExecutionContext dependencies
let typeDesign = MultiAgentSystem.AskTypeDesign stepTask name version metaContext
printfn "[Пайплайн] Элемент: %s_%d_%d_%d | Зависимостей: %d" name version.Major version.Minor version.Patch dependencies.Length
try
let finalizedResponse =
runClosedGenerationLoop stepTask metaContext isolatedCodeContext name version dependencies typeDesign "" 0
match DatabaseRegistry.saveComponent finalizedResponse with
| Some _ -> true
| None -> false
with ex ->
printfn "[Критическая ошибка шага] %s" ex.Message
false
let rec executeCoordinatorLoop userTask history =
let metaContext = DatabaseRegistry.getLatestRegistryMetadataOnly()
match MultiAgentSystem.AskCoordinator userTask metaContext history with
| Some coord when coord.Action = "done" ->
printfn "\n[Координатор] Ура! Все компоненты для задачи успешно построены."
| Some coord when coord.Action = "next_step" ->
printfn "\n--- [Координатор выдал шаг]: %s ---" coord.Step
if runSingleWorkflowStep coord.Step then
let newHistory = history @ [ sprintf "Успешно выполнено: %s" coord.Step ]
executeCoordinatorLoop userTask newHistory
else
printfn "[Ошибка] Шаг провален. Попробуем перепланировать..."
let newHistory = history @ [ sprintf "Ошибка выполнения: %s" coord.Step ]
executeCoordinatorLoop userTask newHistory
| _ -> printfn "[Координатор] Не удалось получить внятное решение от ИИ."
// ============================================================
// 7. ТОЧКА ВХОДА
// ============================================================
[<EntryPoint>]
let main argv =
printfn "=== МНОГОАГЕНТНАЯ GAC СИСТЕМА F# АКТИВИРОВАНА ==="
DatabaseRegistry.initDatabase()
let userTask =
if argv.Length > 0 then
String.concat " " argv
else
"Создай структуру данных для хранения результатов банковской транзакции (успех с GUID транзакции, либо ошибка с кодом) и чистую функцию для безопасного перевода средств, которая принимает баланс и сумму списания."
printfn "[Исходный запрос]: %s\n" userTask
executeCoordinatorLoop userTask []
0