x-ipe 1.0.24__py3-none-any.whl → 1.0.25__py3-none-any.whl

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 (139) hide show
  1. x_ipe/app.py +25 -3
  2. x_ipe/handlers/terminal_handlers.py +6 -0
  3. x_ipe/handlers/voice_handlers.py +5 -0
  4. x_ipe/resources/copilot-instructions.md +19 -6
  5. x_ipe/resources/skills/lesson-learned/SKILL.md +208 -0
  6. x_ipe/resources/skills/lesson-learned/references/examples.md +238 -0
  7. x_ipe/resources/skills/project-quality-board-management/SKILL.md +135 -298
  8. x_ipe/resources/skills/project-quality-board-management/references/evaluation-principles.md +213 -0
  9. x_ipe/resources/skills/project-quality-board-management/references/evaluation-procedures.md +214 -0
  10. x_ipe/resources/skills/project-quality-board-management/templates/quality-report.md +70 -18
  11. x_ipe/resources/skills/task-execution-guideline/SKILL.md +2 -2
  12. x_ipe/resources/skills/task-execution-guideline/templates/task-record.yaml +1 -1
  13. x_ipe/resources/skills/task-type-code-implementation/SKILL.md +72 -270
  14. x_ipe/resources/skills/task-type-code-implementation/references/implementation-guidelines.md +432 -0
  15. x_ipe/resources/skills/task-type-code-refactor-v2/SKILL.md +127 -353
  16. x_ipe/resources/skills/task-type-code-refactor-v2/references/refactoring-techniques.md +373 -0
  17. x_ipe/resources/skills/task-type-feature-breakdown/SKILL.md +31 -243
  18. x_ipe/resources/skills/task-type-feature-breakdown/references/breakdown-guidelines.md +330 -0
  19. x_ipe/resources/skills/task-type-feature-refinement/SKILL.md +27 -180
  20. x_ipe/resources/skills/task-type-feature-refinement/references/specification-writing-guide.md +267 -0
  21. x_ipe/resources/skills/task-type-idea-mockup/SKILL.md +38 -276
  22. x_ipe/resources/skills/task-type-idea-mockup/references/mockup-guidelines.md +299 -0
  23. x_ipe/resources/skills/task-type-idea-to-architecture/SKILL.md +20 -218
  24. x_ipe/resources/skills/task-type-idea-to-architecture/references/architecture-patterns.md +342 -0
  25. x_ipe/resources/skills/task-type-ideation/SKILL.md +10 -266
  26. x_ipe/resources/skills/task-type-ideation/references/folder-naming-guide.md +55 -0
  27. x_ipe/resources/skills/task-type-ideation/references/tool-usage-guide.md +236 -0
  28. x_ipe/resources/skills/task-type-ideation-v2/SKILL.md +488 -0
  29. x_ipe/resources/skills/task-type-ideation-v2/references/examples.md +377 -0
  30. x_ipe/resources/skills/task-type-ideation-v2/references/folder-naming-guide.md +74 -0
  31. x_ipe/resources/skills/task-type-ideation-v2/references/tool-usage-guide.md +145 -0
  32. x_ipe/resources/skills/task-type-ideation-v2/references/visualization-guide.md +160 -0
  33. x_ipe/resources/skills/task-type-ideation-v2/templates/idea-summary.md +86 -0
  34. x_ipe/resources/skills/task-type-refactoring-analysis/SKILL.md +83 -145
  35. x_ipe/resources/skills/task-type-refactoring-analysis/references/output-schema.md +172 -0
  36. x_ipe/resources/skills/task-type-technical-design/SKILL.md +28 -214
  37. x_ipe/resources/skills/task-type-technical-design/references/design-templates.md +422 -0
  38. x_ipe/resources/skills/task-type-test-generation/SKILL.md +47 -332
  39. x_ipe/resources/skills/task-type-test-generation/references/test-patterns.md +368 -0
  40. x_ipe/resources/skills/tool-tracing-creator/SKILL.md +312 -0
  41. x_ipe/resources/skills/tool-tracing-creator/references/examples.md +324 -0
  42. x_ipe/resources/skills/tool-tracing-instrumentation/SKILL.md +373 -0
  43. x_ipe/resources/skills/tool-tracing-instrumentation/references/examples.md +264 -0
  44. x_ipe/resources/skills/x-ipe-skill-creator-v3/SKILL.md +486 -0
  45. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/10. example-gate-conditions.md +73 -0
  46. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/11. reference-quality-standards.md +127 -0
  47. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/2. reference-section-order.md +127 -0
  48. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/3. example-step-based-code-review.md +84 -0
  49. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/4. example-step-based-feature-implementation.md +113 -0
  50. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/5. example-function-based-validation.md +73 -0
  51. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/6. example-function-based-analysis.md +94 -0
  52. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/7. example-task-io-code-implementation.md +36 -0
  53. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/8. example-structured-summary.md +43 -0
  54. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/9. example-dor-dod.md +77 -0
  55. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/examples.md +429 -0
  56. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/skill-general-guidelines-v2.md +611 -0
  57. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/skill-meta-x-ipe-meta.md +153 -0
  58. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/skill-meta-x-ipe-task-based.md +324 -0
  59. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/skill-meta-x-ipe-task-category.md +109 -0
  60. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/skill-meta-x-ipe-tool.md +205 -0
  61. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/x-ipe-meta.md +334 -0
  62. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/x-ipe-task-based.md +279 -0
  63. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/x-ipe-tool.md +175 -0
  64. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/x-ipe-workflow-orchestration.md +329 -0
  65. x_ipe/resources/skills/x-ipe-task-based-ideation/SKILL.md +487 -0
  66. x_ipe/resources/skills/x-ipe-task-based-ideation/references/examples.md +377 -0
  67. x_ipe/resources/skills/x-ipe-task-based-ideation/references/folder-naming-guide.md +74 -0
  68. x_ipe/resources/skills/x-ipe-task-based-ideation/references/tool-usage-guide.md +145 -0
  69. x_ipe/resources/skills/x-ipe-task-based-ideation/references/visualization-guide.md +160 -0
  70. x_ipe/resources/skills/x-ipe-task-based-ideation/templates/idea-summary.md +86 -0
  71. x_ipe/routes/__init__.py +2 -0
  72. x_ipe/routes/ideas_routes.py +17 -0
  73. x_ipe/routes/kb_routes.py +80 -0
  74. x_ipe/routes/main_routes.py +18 -0
  75. x_ipe/routes/project_routes.py +7 -0
  76. x_ipe/routes/proxy_routes.py +2 -0
  77. x_ipe/routes/quality_evaluation_routes.py +193 -0
  78. x_ipe/routes/settings_routes.py +6 -0
  79. x_ipe/routes/tools_routes.py +6 -0
  80. x_ipe/routes/tracing_routes.py +232 -0
  81. x_ipe/routes/uiux_feedback_routes.py +30 -0
  82. x_ipe/services/__init__.py +5 -0
  83. x_ipe/services/config_service.py +6 -0
  84. x_ipe/services/file_service.py +20 -0
  85. x_ipe/services/homepage_service.py +160 -0
  86. x_ipe/services/ideas_service.py +19 -0
  87. x_ipe/services/kb_service.py +378 -0
  88. x_ipe/services/proxy_service.py +4 -0
  89. x_ipe/services/settings_service.py +13 -0
  90. x_ipe/services/skills_service.py +4 -0
  91. x_ipe/services/terminal_service.py +24 -0
  92. x_ipe/services/themes_service.py +4 -0
  93. x_ipe/services/tools_config_service.py +4 -0
  94. x_ipe/services/tracing_service.py +333 -0
  95. x_ipe/services/uiux_feedback_service.py +32 -0
  96. x_ipe/services/voice_input_service_v2.py +11 -0
  97. x_ipe/static/css/base.css +7 -0
  98. x_ipe/static/css/homepage-infinity.css +330 -0
  99. x_ipe/static/css/kb-core.css +301 -0
  100. x_ipe/static/css/quality-evaluation.css +345 -0
  101. x_ipe/static/css/sidebar.css +14 -4
  102. x_ipe/static/css/terminal.css +1 -0
  103. x_ipe/static/css/tracing-dashboard.css +796 -0
  104. x_ipe/static/css/workplace.css +20 -0
  105. x_ipe/static/img/homepage-infinity-loop.png +0 -0
  106. x_ipe/static/js/features/homepage-infinity.js +314 -0
  107. x_ipe/static/js/features/kb-core.js +371 -0
  108. x_ipe/static/js/features/quality-evaluation.js +387 -0
  109. x_ipe/static/js/features/sidebar.js +255 -12
  110. x_ipe/static/js/features/tracing-dashboard.js +855 -0
  111. x_ipe/static/js/features/tracing-graph.js +1031 -0
  112. x_ipe/static/js/features/tree-search.js +6 -2
  113. x_ipe/static/js/features/workplace.js +200 -6
  114. x_ipe/static/js/init.js +76 -0
  115. x_ipe/static/js/uiux-feedback.js +18 -2
  116. x_ipe/templates/base.html +19 -0
  117. x_ipe/templates/index.html +7 -1
  118. x_ipe/templates/knowledge-base.html +110 -0
  119. x_ipe/templates/workplace.html +4 -0
  120. x_ipe/tracing/__init__.py +37 -0
  121. x_ipe/tracing/buffer.py +135 -0
  122. x_ipe/tracing/context.py +125 -0
  123. x_ipe/tracing/decorator.py +288 -0
  124. x_ipe/tracing/middleware.py +197 -0
  125. x_ipe/tracing/parser.py +235 -0
  126. x_ipe/tracing/redactor.py +111 -0
  127. x_ipe/tracing/writer.py +122 -0
  128. {x_ipe-1.0.24.dist-info → x_ipe-1.0.25.dist-info}/METADATA +2 -2
  129. {x_ipe-1.0.24.dist-info → x_ipe-1.0.25.dist-info}/RECORD +132 -62
  130. x_ipe/resources/skills/x-ipe-skill-creator/SKILL.md +0 -329
  131. x_ipe/resources/skills/x-ipe-skill-creator/references/output-patterns.md +0 -169
  132. x_ipe/resources/skills/x-ipe-skill-creator/references/skill-structure.md +0 -162
  133. x_ipe/resources/skills/x-ipe-skill-creator/references/workflows.md +0 -110
  134. x_ipe/resources/skills/x-ipe-skill-creator/templates/references/examples.md +0 -113
  135. x_ipe/resources/skills/x-ipe-skill-creator/templates/skill-category-skill.md +0 -296
  136. x_ipe/resources/skills/x-ipe-skill-creator/templates/task-type-skill.md +0 -269
  137. {x_ipe-1.0.24.dist-info → x_ipe-1.0.25.dist-info}/WHEEL +0 -0
  138. {x_ipe-1.0.24.dist-info → x_ipe-1.0.25.dist-info}/entry_points.txt +0 -0
  139. {x_ipe-1.0.24.dist-info → x_ipe-1.0.25.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,135 @@
1
+ """
2
+ FEATURE-023: Application Action Tracing - Core
3
+
4
+ TraceBuffer and TraceEntry for in-memory trace storage.
5
+
6
+ Traces are collected in-memory during request execution and flushed
7
+ to log files upon request completion.
8
+ """
9
+ from dataclasses import dataclass, field
10
+ from datetime import datetime, timezone
11
+ from typing import List, Optional, Any
12
+ import json
13
+
14
+
15
+ @dataclass
16
+ class TraceEntry:
17
+ """
18
+ Single trace log entry representing a function call event.
19
+
20
+ Attributes:
21
+ timestamp: When the event occurred
22
+ trace_id: Unique identifier for the trace
23
+ level: Log level (INFO, DEBUG, ERROR)
24
+ direction: Arrow direction (→ for entry, ← for exit)
25
+ event_type: Type of event (start_function, return_function, exception)
26
+ function_name: Name of the traced function
27
+ data: Parameters, return value, or error details
28
+ duration_ms: Execution time in milliseconds (only for exit events)
29
+ depth: Nesting level (0 = root)
30
+ """
31
+ timestamp: datetime
32
+ trace_id: str
33
+ level: str
34
+ direction: str
35
+ event_type: str
36
+ function_name: str
37
+ data: dict
38
+ duration_ms: Optional[float] = None
39
+ depth: int = 0
40
+
41
+
42
+ class TraceBuffer:
43
+ """
44
+ In-memory buffer for trace entries during request execution.
45
+
46
+ Collects trace entries and formats them for log file output.
47
+ Enforces a maximum size limit to prevent memory exhaustion.
48
+
49
+ Usage:
50
+ buffer = TraceBuffer("abc-123", "POST /api/orders")
51
+ buffer.add(TraceEntry(...))
52
+ log_content = buffer.to_log_string("SUCCESS", 150.0)
53
+ """
54
+
55
+ MAX_SIZE = 10 * 1024 * 1024 # 10MB limit
56
+
57
+ def __init__(self, trace_id: str, root_api: str):
58
+ """
59
+ Initialize TraceBuffer.
60
+
61
+ Args:
62
+ trace_id: Unique identifier for this trace
63
+ root_api: The root API call (e.g., "POST /api/orders")
64
+ """
65
+ self.trace_id = trace_id
66
+ self.root_api = root_api
67
+ self.started_at = datetime.now(timezone.utc)
68
+ self.entries: List[TraceEntry] = []
69
+ self._size = 0
70
+
71
+ def add(self, entry: TraceEntry) -> None:
72
+ """
73
+ Add a trace entry to the buffer.
74
+
75
+ Silently drops entries if buffer size limit is exceeded.
76
+
77
+ Args:
78
+ entry: TraceEntry to add
79
+ """
80
+ try:
81
+ entry_size = len(json.dumps(entry.data, default=str))
82
+ except (TypeError, ValueError):
83
+ entry_size = 100 # Fallback size estimate
84
+
85
+ if self._size + entry_size > self.MAX_SIZE:
86
+ return # Silently drop if buffer full
87
+
88
+ self.entries.append(entry)
89
+ self._size += entry_size
90
+
91
+ def to_log_string(self, status: str, total_ms: float) -> str:
92
+ """
93
+ Format the buffer as a log file string.
94
+
95
+ Args:
96
+ status: Final status (SUCCESS, ERROR)
97
+ total_ms: Total execution time in milliseconds
98
+
99
+ Returns:
100
+ Formatted log string ready for file output
101
+ """
102
+ lines = [
103
+ f"[TRACE-START] {self.trace_id} | {self.root_api} | {self.started_at.isoformat()}Z"
104
+ ]
105
+
106
+ for entry in self.entries:
107
+ indent = " " * (entry.depth + 1)
108
+
109
+ try:
110
+ data_str = json.dumps(entry.data, default=str, ensure_ascii=False)
111
+ except (TypeError, ValueError):
112
+ data_str = str(entry.data)
113
+
114
+ # Truncate very long data
115
+ if len(data_str) > 1000:
116
+ data_str = data_str[:997] + "..."
117
+
118
+ if entry.duration_ms is not None:
119
+ line = (
120
+ f"{indent}[{entry.level}] {entry.direction} {entry.event_type}: "
121
+ f"{entry.function_name} | {data_str} | {entry.duration_ms:.0f}ms"
122
+ )
123
+ else:
124
+ line = (
125
+ f"{indent}[{entry.level}] {entry.direction} {entry.event_type}: "
126
+ f"{entry.function_name} | {data_str}"
127
+ )
128
+
129
+ lines.append(line)
130
+
131
+ lines.append(
132
+ f"[TRACE-END] {self.trace_id} | {total_ms:.0f}ms | {status}"
133
+ )
134
+
135
+ return "\n".join(lines)
@@ -0,0 +1,125 @@
1
+ """
2
+ FEATURE-023: Application Action Tracing - Core
3
+
4
+ TraceContext for thread-safe context propagation using contextvars.
5
+
6
+ Manages the active trace context across nested function calls,
7
+ ensuring trace ID propagation and proper nesting depth tracking.
8
+ """
9
+ from contextvars import ContextVar
10
+ from typing import Optional, List
11
+ import uuid
12
+
13
+ from .buffer import TraceBuffer
14
+
15
+
16
+ # Thread-safe context variable for the active trace
17
+ _trace_context: ContextVar[Optional['TraceContext']] = ContextVar(
18
+ 'trace_context',
19
+ default=None
20
+ )
21
+
22
+
23
+ class TraceContext:
24
+ """
25
+ Thread-safe trace context manager.
26
+
27
+ Uses Python's contextvars to maintain trace state across async
28
+ function calls. Tracks trace ID, buffer, and call depth.
29
+
30
+ Usage:
31
+ # Start a new trace
32
+ ctx = TraceContext.start_trace("POST /api/orders")
33
+
34
+ # Get current context (in nested calls)
35
+ ctx = TraceContext.get_current()
36
+
37
+ # End trace and get buffer
38
+ buffer = TraceContext.end_trace()
39
+ """
40
+
41
+ def __init__(self, trace_id: str, root_api: str):
42
+ """
43
+ Initialize TraceContext.
44
+
45
+ Args:
46
+ trace_id: Unique identifier for this trace
47
+ root_api: The root API call (e.g., "POST /api/orders")
48
+ """
49
+ self.trace_id = trace_id
50
+ self.buffer = TraceBuffer(trace_id, root_api)
51
+ self.depth = 0
52
+ self._call_stack: List[str] = []
53
+
54
+ @classmethod
55
+ def start_trace(cls, root_api: str) -> 'TraceContext':
56
+ """
57
+ Start a new trace.
58
+
59
+ Generates a unique trace ID and creates a new context.
60
+ Sets the context as the active trace.
61
+
62
+ Args:
63
+ root_api: The root API call (e.g., "POST /api/orders")
64
+
65
+ Returns:
66
+ New TraceContext instance
67
+ """
68
+ # Generate short UUID for readability (first 13 chars)
69
+ trace_id = str(uuid.uuid4())[:13]
70
+ ctx = cls(trace_id, root_api)
71
+ _trace_context.set(ctx)
72
+ return ctx
73
+
74
+ @classmethod
75
+ def get_current(cls) -> Optional['TraceContext']:
76
+ """
77
+ Get the current active trace context.
78
+
79
+ Returns:
80
+ Active TraceContext or None if no trace is active
81
+ """
82
+ return _trace_context.get()
83
+
84
+ @classmethod
85
+ def end_trace(cls) -> Optional[TraceBuffer]:
86
+ """
87
+ End the current trace and return the buffer.
88
+
89
+ Clears the active context.
90
+
91
+ Returns:
92
+ TraceBuffer containing all trace entries, or None if no active trace
93
+ """
94
+ ctx = _trace_context.get()
95
+ if ctx:
96
+ _trace_context.set(None)
97
+ return ctx.buffer
98
+ return None
99
+
100
+ def push_call(self, func_name: str) -> int:
101
+ """
102
+ Push a function call onto the stack.
103
+
104
+ Increments depth and tracks the function name.
105
+
106
+ Args:
107
+ func_name: Name of the function being called
108
+
109
+ Returns:
110
+ Depth level before increment (for logging)
111
+ """
112
+ self._call_stack.append(func_name)
113
+ depth = self.depth
114
+ self.depth += 1
115
+ return depth
116
+
117
+ def pop_call(self) -> None:
118
+ """
119
+ Pop a function call from the stack.
120
+
121
+ Decrements depth and removes the function from tracking.
122
+ """
123
+ if self._call_stack:
124
+ self._call_stack.pop()
125
+ self.depth -= 1
@@ -0,0 +1,288 @@
1
+ """
2
+ FEATURE-023: Application Action Tracing - Core
3
+
4
+ @x_ipe_tracing decorator for automatic function tracing.
5
+
6
+ Provides a decorator that automatically logs function entry, exit,
7
+ return values, and exceptions with execution timing.
8
+ """
9
+ import functools
10
+ import time
11
+ import asyncio
12
+ import inspect
13
+ from datetime import datetime, timezone
14
+ from typing import Callable, List, Optional, Any, Dict
15
+
16
+ from .context import TraceContext
17
+ from .buffer import TraceEntry
18
+ from .redactor import Redactor
19
+
20
+
21
+ def x_ipe_tracing(
22
+ level: str = "INFO",
23
+ redact: Optional[List[str]] = None
24
+ ) -> Callable:
25
+ """
26
+ Decorator for automatic function tracing.
27
+
28
+ Logs function entry with parameters, exit with return value,
29
+ and any exceptions that occur. Automatically redacts sensitive data.
30
+
31
+ Args:
32
+ level: Log level - "INFO", "DEBUG", or "SKIP"
33
+ redact: List of parameter names to redact (in addition to built-in patterns)
34
+
35
+ Usage:
36
+ @x_ipe_tracing(level="INFO", redact=["password"])
37
+ def create_user(email: str, password: str) -> dict:
38
+ ...
39
+
40
+ Returns:
41
+ Decorated function that traces execution
42
+ """
43
+ if level == "SKIP":
44
+ return lambda fn: fn # No-op decorator
45
+
46
+ redactor = Redactor(custom_fields=redact)
47
+
48
+ def decorator(func: Callable) -> Callable:
49
+ @functools.wraps(func)
50
+ def sync_wrapper(*args, **kwargs):
51
+ ctx = TraceContext.get_current()
52
+ if not ctx:
53
+ return func(*args, **kwargs) # No active trace
54
+
55
+ return _trace_call(ctx, func, args, kwargs, level, redactor)
56
+
57
+ @functools.wraps(func)
58
+ async def async_wrapper(*args, **kwargs):
59
+ ctx = TraceContext.get_current()
60
+ if not ctx:
61
+ return await func(*args, **kwargs) # No active trace
62
+
63
+ return await _trace_call_async(ctx, func, args, kwargs, level, redactor)
64
+
65
+ if asyncio.iscoroutinefunction(func):
66
+ return async_wrapper
67
+ return sync_wrapper
68
+
69
+ return decorator
70
+
71
+
72
+ def _extract_params(func: Callable, args: tuple, kwargs: dict) -> Dict[str, Any]:
73
+ """
74
+ Extract function parameters as a dictionary.
75
+
76
+ Uses function signature to map positional args to parameter names.
77
+
78
+ Args:
79
+ func: The function being called
80
+ args: Positional arguments
81
+ kwargs: Keyword arguments
82
+
83
+ Returns:
84
+ Dictionary of parameter names to values
85
+ """
86
+ params = {}
87
+
88
+ try:
89
+ sig = inspect.signature(func)
90
+ param_names = list(sig.parameters.keys())
91
+
92
+ # Map positional args
93
+ for i, arg in enumerate(args):
94
+ if i < len(param_names):
95
+ # Skip 'self' and 'cls' parameters
96
+ param_name = param_names[i]
97
+ if param_name not in ('self', 'cls'):
98
+ params[param_name] = arg
99
+ else:
100
+ params[f"arg_{i}"] = arg
101
+
102
+ # Add keyword args
103
+ params.update(kwargs)
104
+ except (ValueError, TypeError):
105
+ # Fallback if signature introspection fails
106
+ for i, arg in enumerate(args):
107
+ params[f"arg_{i}"] = arg
108
+ params.update(kwargs)
109
+
110
+ return params
111
+
112
+
113
+ def _safe_serialize(value: Any) -> Any:
114
+ """
115
+ Safely serialize a value for logging.
116
+
117
+ Handles circular references and non-serializable objects.
118
+
119
+ Args:
120
+ value: Value to serialize
121
+
122
+ Returns:
123
+ Serializable representation of the value
124
+ """
125
+ try:
126
+ # Try direct serialization
127
+ import json
128
+ json.dumps(value, default=str)
129
+ return value
130
+ except (TypeError, ValueError, RecursionError):
131
+ # Fallback for complex objects
132
+ return str(value)[:500]
133
+
134
+
135
+ def _trace_call(
136
+ ctx: TraceContext,
137
+ func: Callable,
138
+ args: tuple,
139
+ kwargs: dict,
140
+ level: str,
141
+ redactor: Redactor
142
+ ) -> Any:
143
+ """
144
+ Trace a synchronous function call.
145
+
146
+ Logs entry, executes the function, logs exit or exception.
147
+ """
148
+ func_name = func.__name__
149
+ depth = ctx.push_call(func_name)
150
+
151
+ # Extract and redact parameters
152
+ params = _extract_params(func, args, kwargs)
153
+ redacted_params = redactor.redact(params)
154
+
155
+ # Log entry
156
+ ctx.buffer.add(TraceEntry(
157
+ timestamp=datetime.now(timezone.utc),
158
+ trace_id=ctx.trace_id,
159
+ level=level,
160
+ direction="→",
161
+ event_type="start_function",
162
+ function_name=func_name,
163
+ data=_safe_serialize(redacted_params),
164
+ depth=depth
165
+ ))
166
+
167
+ start = time.perf_counter()
168
+ try:
169
+ result = func(*args, **kwargs)
170
+ duration = (time.perf_counter() - start) * 1000
171
+
172
+ # Redact and serialize return value
173
+ redacted_result = redactor.redact({"return": _safe_serialize(result)})
174
+
175
+ # Log success
176
+ ctx.buffer.add(TraceEntry(
177
+ timestamp=datetime.now(timezone.utc),
178
+ trace_id=ctx.trace_id,
179
+ level=level,
180
+ direction="←",
181
+ event_type="return_function",
182
+ function_name=func_name,
183
+ data=redacted_result,
184
+ duration_ms=duration,
185
+ depth=depth
186
+ ))
187
+ return result
188
+
189
+ except Exception as e:
190
+ duration = (time.perf_counter() - start) * 1000
191
+
192
+ # Log error
193
+ ctx.buffer.add(TraceEntry(
194
+ timestamp=datetime.now(timezone.utc),
195
+ trace_id=ctx.trace_id,
196
+ level="ERROR",
197
+ direction="←",
198
+ event_type="exception",
199
+ function_name=func_name,
200
+ data={
201
+ "error": type(e).__name__,
202
+ "message": str(e)
203
+ },
204
+ duration_ms=duration,
205
+ depth=depth
206
+ ))
207
+ raise
208
+
209
+ finally:
210
+ ctx.pop_call()
211
+
212
+
213
+ async def _trace_call_async(
214
+ ctx: TraceContext,
215
+ func: Callable,
216
+ args: tuple,
217
+ kwargs: dict,
218
+ level: str,
219
+ redactor: Redactor
220
+ ) -> Any:
221
+ """
222
+ Trace an asynchronous function call.
223
+
224
+ Logs entry, awaits the function, logs exit or exception.
225
+ """
226
+ func_name = func.__name__
227
+ depth = ctx.push_call(func_name)
228
+
229
+ # Extract and redact parameters
230
+ params = _extract_params(func, args, kwargs)
231
+ redacted_params = redactor.redact(params)
232
+
233
+ # Log entry
234
+ ctx.buffer.add(TraceEntry(
235
+ timestamp=datetime.now(timezone.utc),
236
+ trace_id=ctx.trace_id,
237
+ level=level,
238
+ direction="→",
239
+ event_type="start_function",
240
+ function_name=func_name,
241
+ data=_safe_serialize(redacted_params),
242
+ depth=depth
243
+ ))
244
+
245
+ start = time.perf_counter()
246
+ try:
247
+ result = await func(*args, **kwargs)
248
+ duration = (time.perf_counter() - start) * 1000
249
+
250
+ # Redact and serialize return value
251
+ redacted_result = redactor.redact({"return": _safe_serialize(result)})
252
+
253
+ # Log success
254
+ ctx.buffer.add(TraceEntry(
255
+ timestamp=datetime.now(timezone.utc),
256
+ trace_id=ctx.trace_id,
257
+ level=level,
258
+ direction="←",
259
+ event_type="return_function",
260
+ function_name=func_name,
261
+ data=redacted_result,
262
+ duration_ms=duration,
263
+ depth=depth
264
+ ))
265
+ return result
266
+
267
+ except Exception as e:
268
+ duration = (time.perf_counter() - start) * 1000
269
+
270
+ # Log error
271
+ ctx.buffer.add(TraceEntry(
272
+ timestamp=datetime.now(timezone.utc),
273
+ trace_id=ctx.trace_id,
274
+ level="ERROR",
275
+ direction="←",
276
+ event_type="exception",
277
+ function_name=func_name,
278
+ data={
279
+ "error": type(e).__name__,
280
+ "message": str(e)
281
+ },
282
+ duration_ms=duration,
283
+ depth=depth
284
+ ))
285
+ raise
286
+
287
+ finally:
288
+ ctx.pop_call()