@@ -62,6 +62,8 @@ A schema-enforced module standard for the AI-Perceivable era.
6262| ` RetryMiddleware ` | Automatic retry with backoff |
6363| ` ErrorHistoryMiddleware ` | Records errors into ErrorHistory |
6464| ` PlatformNotifyMiddleware ` | Emits events on error rate/latency spikes |
65+ | ` ObsLoggingMiddleware ` | Observability-aware structured logging middleware |
66+ | ` UsageMiddleware ` | Per-call usage tracking middleware |
6567
6668** Schema**
6769
@@ -81,6 +83,10 @@ A schema-enforced module standard for the AI-Perceivable era.
8183| ` ContextLogger ` | Context-aware structured logging |
8284| ` ErrorHistory ` | Ring buffer of recent errors with deduplication |
8385| ` UsageCollector ` | Per-module usage statistics and trends |
86+ | ` TraceContext ` | W3C Trace Context propagation (traceparent/tracestate) |
87+ | ` InMemoryExporter ` | Span exporter that stores spans in memory |
88+ | ` StdoutExporter ` | Span exporter that writes spans to stdout |
89+ | ` OTLPExporter ` | Span exporter using OpenTelemetry Protocol |
8490
8591** Events & Extensions**
8692
@@ -92,6 +98,7 @@ A schema-enforced module standard for the AI-Perceivable era.
9298| ` AsyncTaskManager ` | Background module execution with status tracking |
9399| ` CancelToken ` | Cooperative cancellation token |
94100| ` BindingLoader ` | Load modules from YAML binding files |
101+ | ` ErrorCodeRegistry ` | Central registry for structured error codes |
95102
96103## Documentation
97104
@@ -200,29 +207,171 @@ acl = ACL(rules=[
200207executor = Executor(registry = registry, acl = acl)
201208```
202209
203- ## Project Structure
210+ ## Examples
204211
212+ The ` examples/ ` directory contains runnable demos:
213+
214+ ---
215+
216+ ### ` simple_client ` — APCore client with decorator-based modules
217+
218+ Initializes an ` APCore ` client, registers modules with ` @client.module() ` , and calls them directly.
219+
220+ ``` python
221+ from apcore import APCore
222+
223+ client = APCore()
224+
225+ @client.module (id = " math.add" , description = " Add two integers" )
226+ def add (a : int , b : int ) -> int :
227+ return a + b
228+
229+ result = client.call(" math.add" , {" a" : 10 , " b" : 5 })
230+ print (result) # {'result': 15}
231+
232+ @client.module (id = " greet" )
233+ def greet (name : str , greeting : str = " Hello" ) -> dict :
234+ return {" message" : f " { greeting} , { name} ! " }
235+
236+ result = client.call(" greet" , {" name" : " Alice" })
237+ print (result) # {'message': 'Hello, Alice!'}
238+ ```
239+
240+ ---
241+
242+ ### ` global_client ` — Minimal global client usage
243+
244+ No explicit initialization needed — use the default global client directly.
245+
246+ ``` python
247+ import apcore
248+
249+ @apcore.module (id = " math.add" )
250+ def add (a : int , b : int ) -> int :
251+ return a + b
252+
253+ result = apcore.call(" math.add" , {" a" : 10 , " b" : 5 })
254+ print (result) # {'result': 15}
255+ ```
256+
257+ ---
258+
259+ ### ` greet ` — Duck-typed module with Pydantic schemas
260+
261+ Demonstrates the class-based module interface with Pydantic ` BaseModel ` for input/output schemas.
262+
263+ ``` python
264+ from pydantic import BaseModel
265+
266+ class GreetInput (BaseModel ):
267+ name: str
268+
269+ class GreetOutput (BaseModel ):
270+ message: str
271+
272+ class GreetModule :
273+ input_schema = GreetInput
274+ output_schema = GreetOutput
275+ description = " Greet a user by name"
276+
277+ def execute (self , inputs : dict , context ) -> dict :
278+ name = inputs[" name" ]
279+ return {" message" : f " Hello, { name} ! " }
280+ ```
281+
282+ ---
283+
284+ ### ` get_user ` — Readonly module with ` ModuleAnnotations `
285+
286+ Demonstrates behavioral annotations (` readonly ` , ` idempotent ` ) and simulated database lookup.
287+
288+ ``` python
289+ from pydantic import BaseModel
290+ from apcore.module import ModuleAnnotations
291+
292+ class GetUserInput (BaseModel ):
293+ user_id: str
294+
295+ class GetUserOutput (BaseModel ):
296+ id : str
297+ name: str
298+ email: str
299+
300+ class GetUserModule :
301+ input_schema = GetUserInput
302+ output_schema = GetUserOutput
303+ description = " Get user details by ID"
304+ annotations = ModuleAnnotations(readonly = True , idempotent = True )
305+
306+ _users = {
307+ " user-1" : {" id" : " user-1" , " name" : " Alice" , " email" : " alice@example.com" },
308+ " user-2" : {" id" : " user-2" , " name" : " Bob" , " email" : " bob@example.com" },
309+ }
310+
311+ def execute (self , inputs : dict , context ) -> dict :
312+ user_id = inputs[" user_id" ]
313+ user = self ._users.get(user_id)
314+ if user is None :
315+ return {" id" : user_id, " name" : " Unknown" , " email" : " unknown@example.com" }
316+ return dict (user)
317+ ```
318+
319+ ---
320+
321+ ### ` send_email ` — Destructive module with sensitive fields and ContextLogger
322+
323+ Shows ` x-sensitive ` on schema fields (for log redaction), ` ModuleAnnotations ` with metadata, ` ModuleExample ` for AI-perceivable documentation, and ` ContextLogger ` usage.
324+
325+ ``` python
326+ from pydantic import BaseModel, Field
327+ from apcore.module import ModuleAnnotations, ModuleExample
328+ from apcore.observability import ContextLogger
329+
330+ class SendEmailInput (BaseModel ):
331+ to: str
332+ subject: str
333+ body: str
334+ api_key: str = Field(... , json_schema_extra = {" x-sensitive" : True })
335+
336+ class SendEmailOutput (BaseModel ):
337+ status: str
338+ message_id: str
339+
340+ class SendEmailModule :
341+ input_schema = SendEmailInput
342+ output_schema = SendEmailOutput
343+ description = " Send an email message"
344+ tags = [" email" , " communication" , " external" ]
345+ version = " 1.2.0"
346+ metadata = {" provider" : " example-smtp" , " max_retries" : 3 }
347+ annotations = ModuleAnnotations(destructive = True , idempotent = False , open_world = True )
348+ examples = [
349+ ModuleExample(
350+ title = " Send a welcome email" ,
351+ inputs = {" to" : " user@example.com" , " subject" : " Welcome!" , " body" : " ..." , " api_key" : " sk-xxx" },
352+ output = {" status" : " sent" , " message_id" : " msg-12345" },
353+ description = " Sends a welcome email to a new user." ,
354+ ),
355+ ]
356+
357+ def execute (self , inputs : dict , context ) -> dict :
358+ logger = ContextLogger.from_context(context, name = " send_email" )
359+ logger.info(" Sending email" , extra = {" to" : inputs[" to" ], " subject" : inputs[" subject" ]})
360+ message_id = f " msg- { hash (inputs[' to' ]) % 100000 :05d } "
361+ logger.info(" Email sent successfully" , extra = {" message_id" : message_id})
362+ return {" status" : " sent" , " message_id" : message_id}
205363```
206- src/apcore/
207- __init__.py # Public API
208- async_task.py # Background task manager
209- cancel.py # Cooperative cancellation primitives
210- context.py # Execution context & identity
211- executor.py # Core execution engine
212- decorator.py # @module decorator
213- bindings.py # YAML binding loader
214- config.py # Configuration
215- acl.py # Access control
216- approval.py # Approval system
217- extensions.py # Extension point manager
218- errors.py # Error hierarchy
219- module.py # Module annotations & metadata
220- trace_context.py # W3C trace context helpers
221- middleware/ # Middleware system
222- observability/ # Tracing, metrics, logging
223- registry/ # Module discovery & registration
224- schema/ # Schema loading, validation, export
225- utils/ # Utilities
364+
365+ ---
366+
367+ ### ` decorated_add ` — ` @module ` decorator for simple functions
368+
369+ ``` python
370+ from apcore.decorator import module
371+
372+ @module (description = " Add two integers" , tags = [" math" , " utility" ])
373+ def add (a : int , b : int ) -> int :
374+ return a + b
226375```
227376
228377## Development
0 commit comments