agentic-lang 0.2.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.
Files changed (146) hide show
  1. package/COMMUNITY.md +220 -0
  2. package/CONTRIBUTING.md +194 -0
  3. package/FINAL_REPORT.md +398 -0
  4. package/FOR_OTHER_LLMS.md +286 -0
  5. package/IMPROVEMENTS.md +319 -0
  6. package/LAUNCH_GUIDE.md +388 -0
  7. package/LICENSE +21 -0
  8. package/NPM_PUBLISH.md +257 -0
  9. package/PROJECT_COMPLETE.md +414 -0
  10. package/PROJECT_OVERVIEW.md +265 -0
  11. package/PROJECT_TREE.txt +228 -0
  12. package/PUBLISHING_GUIDE.md +426 -0
  13. package/PUBLISH_NOW.md +337 -0
  14. package/QUICKSTART.md +207 -0
  15. package/README.md +195 -0
  16. package/README_ENHANCED.md +329 -0
  17. package/READY_TO_LAUNCH.txt +56 -0
  18. package/REFACTOR_PLAN.md +179 -0
  19. package/ROADMAP.md +201 -0
  20. package/SUMMARY.md +315 -0
  21. package/bin/agentic.js +3 -0
  22. package/blog/001-introducing-agentic.md +382 -0
  23. package/blog/002-confidence-driven-development.md +490 -0
  24. package/blog/003-formal-verification.md +427 -0
  25. package/blog/004-multi-agent-production.md +436 -0
  26. package/dist/cli.d.ts +7 -0
  27. package/dist/cli.d.ts.map +1 -0
  28. package/dist/cli.js +151 -0
  29. package/dist/cli.js.map +1 -0
  30. package/dist/diagnostics/diagnostic.d.ts +115 -0
  31. package/dist/diagnostics/diagnostic.d.ts.map +1 -0
  32. package/dist/diagnostics/diagnostic.js +101 -0
  33. package/dist/diagnostics/diagnostic.js.map +1 -0
  34. package/dist/diagnostics/formatter.d.ts +36 -0
  35. package/dist/diagnostics/formatter.d.ts.map +1 -0
  36. package/dist/diagnostics/formatter.js +263 -0
  37. package/dist/diagnostics/formatter.js.map +1 -0
  38. package/dist/effects/effect-system.d.ts +64 -0
  39. package/dist/effects/effect-system.d.ts.map +1 -0
  40. package/dist/effects/effect-system.js +197 -0
  41. package/dist/effects/effect-system.js.map +1 -0
  42. package/dist/generator/typescript-generator.d.ts +31 -0
  43. package/dist/generator/typescript-generator.d.ts.map +1 -0
  44. package/dist/generator/typescript-generator.js +308 -0
  45. package/dist/generator/typescript-generator.js.map +1 -0
  46. package/dist/index.d.ts +19 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +60 -0
  49. package/dist/index.js.map +1 -0
  50. package/dist/lean4/exporter.d.ts +24 -0
  51. package/dist/lean4/exporter.d.ts.map +1 -0
  52. package/dist/lean4/exporter.js +142 -0
  53. package/dist/lean4/exporter.js.map +1 -0
  54. package/dist/lsp/server.d.ts +6 -0
  55. package/dist/lsp/server.d.ts.map +1 -0
  56. package/dist/lsp/server.js +131 -0
  57. package/dist/lsp/server.js.map +1 -0
  58. package/dist/parser/lexer.d.ts +79 -0
  59. package/dist/parser/lexer.d.ts.map +1 -0
  60. package/dist/parser/lexer.js +296 -0
  61. package/dist/parser/lexer.js.map +1 -0
  62. package/dist/parser/parser-enhanced.d.ts +12 -0
  63. package/dist/parser/parser-enhanced.d.ts.map +1 -0
  64. package/dist/parser/parser-enhanced.js +206 -0
  65. package/dist/parser/parser-enhanced.js.map +1 -0
  66. package/dist/parser/parser.d.ts +34 -0
  67. package/dist/parser/parser.d.ts.map +1 -0
  68. package/dist/parser/parser.js +507 -0
  69. package/dist/parser/parser.js.map +1 -0
  70. package/dist/property-tests/generator-enhanced.d.ts +27 -0
  71. package/dist/property-tests/generator-enhanced.d.ts.map +1 -0
  72. package/dist/property-tests/generator-enhanced.js +209 -0
  73. package/dist/property-tests/generator-enhanced.js.map +1 -0
  74. package/dist/property-tests/generator-fixed.d.ts +2 -0
  75. package/dist/property-tests/generator-fixed.d.ts.map +1 -0
  76. package/dist/property-tests/generator-fixed.js +7 -0
  77. package/dist/property-tests/generator-fixed.js.map +1 -0
  78. package/dist/property-tests/generator.d.ts +28 -0
  79. package/dist/property-tests/generator.d.ts.map +1 -0
  80. package/dist/property-tests/generator.js +284 -0
  81. package/dist/property-tests/generator.js.map +1 -0
  82. package/dist/refinements/refinement-types.d.ts +96 -0
  83. package/dist/refinements/refinement-types.d.ts.map +1 -0
  84. package/dist/refinements/refinement-types.js +234 -0
  85. package/dist/refinements/refinement-types.js.map +1 -0
  86. package/dist/repl.d.ts +21 -0
  87. package/dist/repl.d.ts.map +1 -0
  88. package/dist/repl.js +317 -0
  89. package/dist/repl.js.map +1 -0
  90. package/dist/runtime/agents.d.ts +97 -0
  91. package/dist/runtime/agents.d.ts.map +1 -0
  92. package/dist/runtime/agents.js +258 -0
  93. package/dist/runtime/agents.js.map +1 -0
  94. package/dist/runtime/index.d.ts +98 -0
  95. package/dist/runtime/index.d.ts.map +1 -0
  96. package/dist/runtime/index.js +253 -0
  97. package/dist/runtime/index.js.map +1 -0
  98. package/dist/types-extended.d.ts +197 -0
  99. package/dist/types-extended.d.ts.map +1 -0
  100. package/dist/types-extended.js +7 -0
  101. package/dist/types-extended.js.map +1 -0
  102. package/dist/types.d.ts +129 -0
  103. package/dist/types.d.ts.map +1 -0
  104. package/dist/types.js +6 -0
  105. package/dist/types.js.map +1 -0
  106. package/dist/verification/z3-engine.d.ts +75 -0
  107. package/dist/verification/z3-engine.d.ts.map +1 -0
  108. package/dist/verification/z3-engine.js +234 -0
  109. package/dist/verification/z3-engine.js.map +1 -0
  110. package/examples/advanced-features.agentic +98 -0
  111. package/examples/annotations.agentic +37 -0
  112. package/examples/auth.agentic +53 -0
  113. package/examples/enterprise-example.agentic +360 -0
  114. package/examples/minimal.agentic +3 -0
  115. package/examples/minimal.ts +7 -0
  116. package/examples/ml-pipeline.agentic +350 -0
  117. package/examples/multi-agent-example.agentic +212 -0
  118. package/examples/onboarding-tutorial.agentic +263 -0
  119. package/examples/production-api.agentic +304 -0
  120. package/examples/real-world-chatbot.agentic +351 -0
  121. package/examples/result-handling.agentic +34 -0
  122. package/examples/runtime.ts +24 -0
  123. package/examples/showcase.agentic +22 -0
  124. package/examples/showcase.ts +28 -0
  125. package/examples/simple-test.agentic +4 -0
  126. package/examples/simple-test.ts +7 -0
  127. package/examples/simple.agentic +20 -0
  128. package/examples/test2.agentic +4 -0
  129. package/examples/test2.ts +9 -0
  130. package/examples/test3.agentic +4 -0
  131. package/examples/test3.ts +9 -0
  132. package/package.json +70 -0
  133. package/playground/index.html +221 -0
  134. package/playground/playground.js +291 -0
  135. package/registry/package-registry.ts +319 -0
  136. package/scripts/build.js +50 -0
  137. package/scripts/validate-confidence-mutation.ts +112 -0
  138. package/stdlib/async/promise.agentic +216 -0
  139. package/stdlib/database/pool.agentic +235 -0
  140. package/stdlib/file/io.agentic +194 -0
  141. package/stdlib/http/client.agentic +168 -0
  142. package/video-scripts/001-agentic-in-100-seconds.md +175 -0
  143. package/vscode-extension/README.md +67 -0
  144. package/vscode-extension/language-configuration.json +31 -0
  145. package/vscode-extension/package.json +46 -0
  146. package/vscode-extension/syntaxes/agentic.tmLanguage.json +134 -0
@@ -0,0 +1,235 @@
1
+ // Database Connection Pool
2
+ // @agentic/db - Production-grade database access with pooling
3
+
4
+ @module("database")
5
+ @confidence(0.93)
6
+
7
+ type DbConfig {
8
+ host: string
9
+ port: number
10
+ database: string
11
+ user: string
12
+ password: string
13
+ minConnections: number = 2
14
+ maxConnections: number = 10
15
+ acquireTimeout: Duration = 30s
16
+ idleTimeout: Duration = 10m
17
+ connectionLifetime: Duration = 1h
18
+ }
19
+
20
+ @effects(database, async, io)
21
+ type Connection {
22
+ @confidence(0.95)
23
+ @property("handles SQL injection safely")
24
+ @property("validates parameters")
25
+ func query<T>(self, sql: string, params: any[]) -> Promise<Result<T[], DbError>> {
26
+ // Execute parameterized query
27
+ // Prevents SQL injection via prepared statements
28
+ }
29
+
30
+ @confidence(0.96)
31
+ @property("returns affected row count")
32
+ func execute(self, sql: string, params: any[]) -> Promise<Result<number, DbError>> {
33
+ // Execute non-query statement (INSERT, UPDATE, DELETE)
34
+ // Returns number of affected rows
35
+ }
36
+
37
+ @confidence(0.99)
38
+ @effects(io)
39
+ func close(self) -> Promise<void> {
40
+ // Close database connection
41
+ // Returns connection to pool
42
+ }
43
+ }
44
+
45
+ @effects(database, async, state)
46
+ type Transaction {
47
+ @confidence(0.94)
48
+ func query<T>(self, sql: string, params: any[]) -> Promise<Result<T[], DbError>>
49
+
50
+ @confidence(0.94)
51
+ func execute(self, sql: string, params: any[]) -> Promise<Result<number, DbError>>
52
+
53
+ @confidence(0.96)
54
+ @property("commits all changes or none")
55
+ func commit(self) -> Promise<Result<void, DbError>> {
56
+ // Commit transaction
57
+ // All-or-nothing guarantee
58
+ }
59
+
60
+ @confidence(0.97)
61
+ @property("rolls back all changes")
62
+ func rollback(self) -> Promise<Result<void, DbError>> {
63
+ // Rollback transaction
64
+ // Cancels all pending changes
65
+ }
66
+ }
67
+
68
+ @needs(config: DbConfig)
69
+ @effects(database, async, state, io)
70
+ type ConnectionPool {
71
+ config: DbConfig
72
+
73
+ @confidence(0.92)
74
+ @property("returns connection within timeout")
75
+ @property("recycles connections")
76
+ @property("limits max connections")
77
+ func acquire(self) -> Promise<Result<Connection, DbError>> {
78
+ @timeout(self.config.acquireTimeout)
79
+ conn = self.getOrCreateConnection()
80
+
81
+ if conn.isStale() {
82
+ conn.refresh()
83
+ }
84
+
85
+ return Ok(conn)
86
+ }
87
+
88
+ @confidence(0.97)
89
+ @property("connection returned to pool")
90
+ func release(self, conn: Connection) -> Promise<void> {
91
+ if self.pool.size() < self.config.maxConnections {
92
+ self.pool.add(conn)
93
+ } else {
94
+ conn.close()
95
+ }
96
+ }
97
+
98
+ @confidence(0.94)
99
+ @complete
100
+ @property("commits on success, rolls back on error")
101
+ @property("releases connection after transaction")
102
+ func transaction<T>(
103
+ self,
104
+ fn: (tx: Transaction) -> Promise<Result<T, Error>>
105
+ ) -> Promise<Result<T, DbError>> {
106
+ conn = self.acquire() match {
107
+ Ok(c) -> c,
108
+ Err(e) -> return Err(e)
109
+ }
110
+
111
+ tx = conn.beginTransaction()
112
+
113
+ result = fn(tx) match {
114
+ Ok(value) -> {
115
+ tx.commit() match {
116
+ Ok(_) -> Ok(value),
117
+ Err(e) -> {
118
+ tx.rollback()
119
+ Err(DbError.COMMIT_FAILED(e))
120
+ }
121
+ }
122
+ },
123
+ Err(error) -> {
124
+ tx.rollback()
125
+ Err(DbError.TRANSACTION_FAILED(error))
126
+ }
127
+ }
128
+
129
+ self.release(conn)
130
+
131
+ return result
132
+ }
133
+
134
+ @healthcheck(interval: 30s)
135
+ @confidence(0.96)
136
+ func checkHealth(self) -> HealthStatus {
137
+ try {
138
+ conn = self.acquire()
139
+ conn.query("SELECT 1", [])
140
+ self.release(conn)
141
+ return HealthStatus.OK
142
+ } catch {
143
+ return HealthStatus.FAILED
144
+ }
145
+ }
146
+
147
+ @confidence(0.98)
148
+ func getTotalConnections(self) -> number {
149
+ return self.pool.size() + self.active.size()
150
+ }
151
+
152
+ @confidence(0.99)
153
+ func getIdleConnections(self) -> number {
154
+ return self.pool.size()
155
+ }
156
+
157
+ @confidence(0.99)
158
+ func getActiveConnections(self) -> number {
159
+ return self.active.size()
160
+ }
161
+ }
162
+
163
+ // Factory function
164
+ @confidence(0.94)
165
+ @complete
166
+ @effects(database, async)
167
+ func createPool(config: DbConfig) -> Promise<Result<ConnectionPool, DbError>> {
168
+ pool = ConnectionPool { config: config }
169
+
170
+ // Initialize minimum connections
171
+ for i in 0..config.minConnections {
172
+ conn = pool.createConnection()
173
+ pool.pool.add(conn)
174
+ }
175
+
176
+ return Ok(pool)
177
+ }
178
+
179
+ // Query builder (type-safe SQL)
180
+ @confidence(0.89)
181
+ @partial("Basic SELECT only, no JOIN/GROUP BY yet")
182
+ type QueryBuilder<T> {
183
+ table: string
184
+ conditions: Condition[]
185
+ limit: Option<number>
186
+
187
+ func where(self, field: string, op: string, value: any) -> QueryBuilder<T> {
188
+ self.conditions.push({ field, op, value })
189
+ return self
190
+ }
191
+
192
+ func limit(self, n: number) -> QueryBuilder<T> {
193
+ self.limit = Some(n)
194
+ return self
195
+ }
196
+
197
+ @confidence(0.90)
198
+ @effects(database, async)
199
+ func execute(self, pool: ConnectionPool) -> Promise<Result<T[], DbError>> {
200
+ sql = self.buildSQL()
201
+ params = self.extractParams()
202
+
203
+ conn = pool.acquire()
204
+ result = conn.query<T>(sql, params)
205
+ pool.release(conn)
206
+
207
+ return result
208
+ }
209
+
210
+ @confidence(0.95)
211
+ private func buildSQL(self) -> string {
212
+ sql = "SELECT * FROM " + self.table
213
+
214
+ if self.conditions.length > 0 {
215
+ sql = sql + " WHERE " + self.conditions.map(c =>
216
+ c.field + " " + c.op + " ?"
217
+ ).join(" AND ")
218
+ }
219
+
220
+ if self.limit {
221
+ sql = sql + " LIMIT " + self.limit
222
+ }
223
+
224
+ return sql
225
+ }
226
+ }
227
+
228
+ @confidence(0.92)
229
+ func select<T>(table: string) -> QueryBuilder<T> {
230
+ return QueryBuilder<T> {
231
+ table: table,
232
+ conditions: [],
233
+ limit: None
234
+ }
235
+ }
@@ -0,0 +1,194 @@
1
+ // File I/O Module
2
+ // @agentic/fs - Buffered file operations with error recovery
3
+
4
+ @module("file")
5
+ @confidence(0.94)
6
+
7
+ type FileMode = "r" | "w" | "a" | "r+" | "w+" | "a+"
8
+
9
+ type WriteOptions {
10
+ overwrite: boolean = false
11
+ createDirectories: boolean = false
12
+ encoding: string = "utf-8"
13
+ }
14
+
15
+ @effects(file_system, async, io)
16
+ @confidence(0.96)
17
+ @complete
18
+ @property("handles missing files")
19
+ @property("handles permission errors")
20
+ @property("respects encoding")
21
+ @needs(fs: FileSystem)
22
+ func readFile(path: string, encoding: string = "utf-8") -> Promise<Result<string, FileError>> {
23
+ if !fs.exists(path) {
24
+ return Err(FileError.NOT_FOUND(path))
25
+ }
26
+
27
+ @retry(maxAttempts: 2, delay: 100ms)
28
+ content = fs.read(path, encoding) or error {
29
+ @context {
30
+ what_failed: "File read",
31
+ path: path,
32
+ encoding: encoding,
33
+ suggestions: [
34
+ "Check file permissions",
35
+ "Verify path is correct",
36
+ "Try different encoding (utf-8, ascii, utf-16)"
37
+ ],
38
+ recovery: {
39
+ action: "use_default",
40
+ command: "echo '' > ${path}"
41
+ }
42
+ }
43
+ return Err(FileError.READ_ERROR(error))
44
+ }
45
+
46
+ return Ok(content)
47
+ }
48
+
49
+ @effects(file_system, async, io)
50
+ @confidence(0.95)
51
+ @complete
52
+ @property("creates parent directories if requested")
53
+ @property("respects overwrite option")
54
+ @property("handles write errors gracefully")
55
+ @needs(fs: FileSystem)
56
+ func writeFile(
57
+ path: string,
58
+ content: string,
59
+ options: WriteOptions = WriteOptions{}
60
+ ) -> Promise<Result<void, FileError>> {
61
+ if fs.exists(path) and !options.overwrite {
62
+ return Err(FileError.ALREADY_EXISTS(path))
63
+ }
64
+
65
+ if options.createDirectories {
66
+ parentDir = path.dirname()
67
+ if !fs.exists(parentDir) {
68
+ fs.createDir(parentDir, recursive: true)
69
+ }
70
+ }
71
+
72
+ @retry(maxAttempts: 2, delay: 100ms)
73
+ fs.write(path, content, options.encoding) or error {
74
+ @context {
75
+ what_failed: "File write",
76
+ path: path,
77
+ size: content.length,
78
+ suggestions: [
79
+ "Check disk space",
80
+ "Verify permissions",
81
+ "Check if path is valid"
82
+ ]
83
+ }
84
+ return Err(FileError.WRITE_ERROR(error))
85
+ }
86
+
87
+ return Ok(void)
88
+ }
89
+
90
+ // Buffered reader for large files
91
+ @effects(file_system, async, io, state)
92
+ type BufferedReader {
93
+ bufferSize: number = 64 * 1024 // 64KB default
94
+
95
+ @confidence(0.95)
96
+ @property("returns None on EOF")
97
+ func readLine(self) -> Promise<Result<Option<string>, IoError>> {
98
+ // Read next line from buffer
99
+ // Returns None when EOF reached
100
+ }
101
+
102
+ @confidence(0.96)
103
+ func readChunk(self, size: number) -> Promise<Result<Buffer, IoError>> {
104
+ // Read exactly size bytes
105
+ // Returns smaller chunk at EOF
106
+ }
107
+
108
+ @confidence(0.94)
109
+ func readAll(self) -> Promise<Result<string, IoError>> {
110
+ lines: string[] = []
111
+
112
+ loop {
113
+ line = self.readLine() match {
114
+ Ok(Some(l)) -> l,
115
+ Ok(None) -> break,
116
+ Err(e) -> return Err(e)
117
+ }
118
+
119
+ lines.push(line)
120
+ }
121
+
122
+ return Ok(lines.join("\n"))
123
+ }
124
+
125
+ @confidence(0.98)
126
+ func close(self) -> Promise<void> {
127
+ // Close file handle and flush buffer
128
+ }
129
+ }
130
+
131
+ // Stream processing for huge files
132
+ @effects(file_system, async, io)
133
+ @confidence(0.92)
134
+ @partial("Memory-efficient but no backpressure yet")
135
+ func stream(path: string) -> AsyncIterator<string> {
136
+ reader = BufferedReader { bufferSize: 64 * 1024 }
137
+
138
+ return async iterator {
139
+ loop {
140
+ line = reader.readLine() match {
141
+ Ok(Some(l)) -> yield l,
142
+ Ok(None) -> return,
143
+ Err(e) -> throw e
144
+ }
145
+ }
146
+ }
147
+ }
148
+
149
+ // Directory operations
150
+ @effects(file_system, io)
151
+ @confidence(0.96)
152
+ @complete
153
+ @property("returns empty array for empty directory")
154
+ @property("handles missing directory")
155
+ func listDir(path: string) -> Promise<Result<string[], FileError>> {
156
+ if !fs.exists(path) {
157
+ return Err(FileError.NOT_FOUND(path))
158
+ }
159
+
160
+ if !fs.isDirectory(path) {
161
+ return Err(FileError.NOT_A_DIRECTORY(path))
162
+ }
163
+
164
+ entries = fs.readDir(path) or error {
165
+ return Err(FileError.READ_ERROR(error))
166
+ }
167
+
168
+ return Ok(entries)
169
+ }
170
+
171
+ @effects(file_system, io)
172
+ @confidence(0.97)
173
+ @complete
174
+ @property("creates directory if not exists")
175
+ @property("handles recursive creation")
176
+ func createDir(path: string, recursive: boolean = false) -> Promise<Result<void, FileError>> {
177
+ if fs.exists(path) {
178
+ return Ok(void) // Already exists
179
+ }
180
+
181
+ options = { recursive: recursive }
182
+
183
+ fs.mkdir(path, options) or error {
184
+ @context {
185
+ what_failed: "Directory creation",
186
+ path: path,
187
+ recursive: recursive,
188
+ suggestions: ["Check parent directory exists", "Verify permissions"]
189
+ }
190
+ return Err(FileError.CREATE_ERROR(error))
191
+ }
192
+
193
+ return Ok(void)
194
+ }
@@ -0,0 +1,168 @@
1
+ // HTTP Client Module
2
+ // @agentic/http - Production-grade HTTP client with connection pooling
3
+
4
+ @module("http")
5
+ @confidence(0.95)
6
+
7
+ type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD"
8
+
9
+ type HttpHeaders = Map<string, string>
10
+
11
+ type HttpRequest {
12
+ method: HttpMethod
13
+ url: string
14
+ headers: HttpHeaders
15
+ body: Option<string>
16
+ timeout: Option<Duration>
17
+ }
18
+
19
+ type HttpResponse {
20
+ status: number
21
+ headers: HttpHeaders
22
+ body: string
23
+
24
+ @confidence(0.98)
25
+ func json<T>(self) -> Result<T, ParseError> {
26
+ return JSON.parse(self.body)
27
+ }
28
+
29
+ @confidence(0.99)
30
+ func text(self) -> string {
31
+ return self.body
32
+ }
33
+ }
34
+
35
+ type HttpClientConfig {
36
+ baseUrl: Option<string>
37
+ defaultHeaders: HttpHeaders
38
+ timeout: Duration = 30s
39
+ maxConnections: number = 100
40
+ keepAlive: boolean = true
41
+ retryPolicy: Option<RetryPolicy>
42
+ }
43
+
44
+ @needs(config: HttpClientConfig)
45
+ @effects(network, async, io)
46
+ type HttpClient {
47
+ config: HttpClientConfig
48
+
49
+ @confidence(0.92)
50
+ @property("handles network errors gracefully")
51
+ @property("respects timeout")
52
+ @property("retries on transient failures")
53
+ func get(self, url: string) -> Promise<Result<HttpResponse, HttpError>> {
54
+ request = HttpRequest {
55
+ method: "GET",
56
+ url: self.resolveUrl(url),
57
+ headers: self.config.defaultHeaders,
58
+ body: None,
59
+ timeout: Some(self.config.timeout)
60
+ }
61
+
62
+ return self.request(request)
63
+ }
64
+
65
+ @confidence(0.92)
66
+ @property("validates request body")
67
+ @property("sets content-type header")
68
+ func post(self, url: string, body: string) -> Promise<Result<HttpResponse, HttpError>> {
69
+ headers = self.config.defaultHeaders.clone()
70
+ headers.set("Content-Type", "application/json")
71
+
72
+ request = HttpRequest {
73
+ method: "POST",
74
+ url: self.resolveUrl(url),
75
+ headers: headers,
76
+ body: Some(body),
77
+ timeout: Some(self.config.timeout)
78
+ }
79
+
80
+ return self.request(request)
81
+ }
82
+
83
+ @confidence(0.90)
84
+ @complete
85
+ @needs(network: NetworkAccess, logger: Logger)
86
+ @effects(network, async, io, exception)
87
+ func request(self, req: HttpRequest) -> Promise<Result<HttpResponse, HttpError>> {
88
+ logger.info("HTTP ${req.method} ${req.url}")
89
+
90
+ @retry(maxAttempts: 3, backoff: "exponential")
91
+ @circuit_breaker(threshold: 5, timeout: 60s)
92
+ response = network.fetch(req.url, {
93
+ method: req.method,
94
+ headers: req.headers,
95
+ body: req.body,
96
+ timeout: req.timeout
97
+ }) match {
98
+ Ok(resp) -> {
99
+ logger.info("HTTP ${req.method} ${req.url} -> ${resp.status}")
100
+ return Ok(resp)
101
+ },
102
+ Err(error) -> {
103
+ @context {
104
+ what_failed: "HTTP request",
105
+ request: { method: req.method, url: req.url },
106
+ suggestions: [
107
+ "Check network connectivity",
108
+ "Verify URL is correct",
109
+ "Check if server is running"
110
+ ],
111
+ recovery: {
112
+ action: "retry",
113
+ command: "http.request(req)"
114
+ }
115
+ }
116
+ logger.error("HTTP ${req.method} ${req.url} failed", error)
117
+ return Err(HttpError.NETWORK_ERROR(error))
118
+ }
119
+ }
120
+ }
121
+
122
+ @confidence(0.99)
123
+ private func resolveUrl(self, path: string) -> string {
124
+ if path.startsWith("http://") or path.startsWith("https://") {
125
+ return path
126
+ }
127
+
128
+ if self.config.baseUrl {
129
+ return self.config.baseUrl + path
130
+ }
131
+
132
+ return path
133
+ }
134
+ }
135
+
136
+ // Factory function
137
+ @confidence(0.98)
138
+ @complete
139
+ func createClient(config: HttpClientConfig) -> HttpClient {
140
+ return HttpClient { config: config }
141
+ }
142
+
143
+ @confidence(0.99)
144
+ func defaultClient() -> HttpClient {
145
+ return createClient(HttpClientConfig {
146
+ baseUrl: None,
147
+ defaultHeaders: Map.new(),
148
+ timeout: Duration.seconds(30),
149
+ maxConnections: 100,
150
+ keepAlive: true,
151
+ retryPolicy: None
152
+ })
153
+ }
154
+
155
+ // Convenience helpers
156
+ @confidence(0.95)
157
+ @effects(network, async)
158
+ func get(url: string) -> Promise<Result<HttpResponse, HttpError>> {
159
+ client = defaultClient()
160
+ return client.get(url)
161
+ }
162
+
163
+ @confidence(0.95)
164
+ @effects(network, async)
165
+ func post(url: string, body: string) -> Promise<Result<HttpResponse, HttpError>> {
166
+ client = defaultClient()
167
+ return client.post(url, body)
168
+ }