pydftracer 2.0.5.post2.dev0__tar.gz → 2.0.6.post2.dev0__tar.gz
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.
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/PKG-INFO +1 -1
- pydftracer-2.0.6.post2.dev0/docs/source/api/agent.rst +109 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/docs/source/api/index.rst +3 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/docs/source/index.rst +1 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/pyproject.toml +3 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/__init__.py +2 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/_version.py +3 -3
- pydftracer-2.0.6.post2.dev0/python/dftracer/python/agent.py +9 -0
- pydftracer-2.0.6.post2.dev0/python/dftracer/python/agent_common.py +381 -0
- pydftracer-2.0.6.post2.dev0/python/dftracer/python/agent_init.py +56 -0
- pydftracer-2.0.6.post2.dev0/python/dftracer/python/agent_langgraph.py +211 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/ai_common.py +60 -67
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/common.py +31 -1
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/dbg/__init__.py +1 -0
- pydftracer-2.0.6.post2.dev0/python/dftracer/python/dbg/agent.py +9 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/pydftracer.egg-info/PKG-INFO +1 -1
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/pydftracer.egg-info/SOURCES.txt +6 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/pydftracer.egg-info/scm_file_list.json +8 -0
- pydftracer-2.0.6.post2.dev0/python/pydftracer.egg-info/scm_version.json +8 -0
- pydftracer-2.0.5.post2.dev0/python/pydftracer.egg-info/scm_version.json +0 -8
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/.readthedocs.yml +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/LICENSE +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/MANIFEST.in +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/NOTICE +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/README.md +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/docs/Makefile +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/docs/README.md +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/docs/make.bat +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/docs/requirements.txt +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/docs/source/ai_ml_guide.rst +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/docs/source/api/ai.rst +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/docs/source/api/core.rst +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/docs/source/api/dynamo.rst +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/docs/source/api/env.rst +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/docs/source/conf.py +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/docs/source/developers.rst +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/docs/source/dynamo_guide.rst +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/docs/source/examples.rst +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/docs/source/installation.rst +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/docs/source/pytorch.rst +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/docs/source/quickstart.rst +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/docs/source/type_safety.rst +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/ai.py +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/ai_init.py +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/dbg/ai.py +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/dbg/logger.py +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/dbg/torch/__init__.py +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/dbg/torch/profiler.py +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/dynamo.py +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/env.py +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/logger.py +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/py.typed +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/torch/__init__.py +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/torch/common.py +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/torch/profiler.py +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/pydftracer.egg-info/dependency_links.txt +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/pydftracer.egg-info/requires.txt +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/pydftracer.egg-info/top_level.txt +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/setup.cfg +0 -0
- {pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pydftracer
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.6.post2.dev0
|
|
4
4
|
Summary: Python libs for DFTracer
|
|
5
5
|
Author-email: "Hariharan Devarajan (Hari)" <hariharandev1@llnl.gov>, Ray Andrew Sinurat <raydreww@gmail.com>
|
|
6
6
|
Maintainer-email: "Hariharan Devarajan (Hari)" <hariharandev1@llnl.gov>, Ray Andrew Sinurat <raydreww@gmail.com>
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
Agent API
|
|
2
|
+
=========
|
|
3
|
+
|
|
4
|
+
This section documents the agent tracing namespace and its event model.
|
|
5
|
+
|
|
6
|
+
Agent Module
|
|
7
|
+
------------
|
|
8
|
+
|
|
9
|
+
The ``agent`` module provides decorators and utilities for tracing agentic workflows.
|
|
10
|
+
|
|
11
|
+
.. automodule:: dftracer.python.agent
|
|
12
|
+
:members:
|
|
13
|
+
:undoc-members:
|
|
14
|
+
|
|
15
|
+
Agent Categories
|
|
16
|
+
----------------
|
|
17
|
+
|
|
18
|
+
.. autoclass:: dftracer.python.AgentCategory
|
|
19
|
+
:members:
|
|
20
|
+
:undoc-members:
|
|
21
|
+
|
|
22
|
+
Agent Components
|
|
23
|
+
----------------
|
|
24
|
+
|
|
25
|
+
.. autoclass:: dftracer.python.Workflow
|
|
26
|
+
:members:
|
|
27
|
+
:undoc-members:
|
|
28
|
+
|
|
29
|
+
.. autoclass:: dftracer.python.AgentStep
|
|
30
|
+
:members:
|
|
31
|
+
:undoc-members:
|
|
32
|
+
|
|
33
|
+
.. autoclass:: dftracer.python.LLM
|
|
34
|
+
:members:
|
|
35
|
+
:undoc-members:
|
|
36
|
+
|
|
37
|
+
.. autoclass:: dftracer.python.Tool
|
|
38
|
+
:members:
|
|
39
|
+
:undoc-members:
|
|
40
|
+
|
|
41
|
+
.. autoclass:: dftracer.python.AgentData
|
|
42
|
+
:members:
|
|
43
|
+
:undoc-members:
|
|
44
|
+
|
|
45
|
+
.. autoclass:: dftracer.python.Message
|
|
46
|
+
:members:
|
|
47
|
+
:undoc-members:
|
|
48
|
+
|
|
49
|
+
.. autoclass:: dftracer.python.Judge
|
|
50
|
+
:members:
|
|
51
|
+
:undoc-members:
|
|
52
|
+
|
|
53
|
+
Agent Instance
|
|
54
|
+
--------------
|
|
55
|
+
|
|
56
|
+
.. autoclass:: dftracer.python.Agent
|
|
57
|
+
:members:
|
|
58
|
+
:undoc-members:
|
|
59
|
+
|
|
60
|
+
Convenience aliases:
|
|
61
|
+
|
|
62
|
+
- ``agent`` - Main agent tracing instance
|
|
63
|
+
- ``workflow`` - Workflow tracing category
|
|
64
|
+
- ``agent_step`` - Agent step tracing category
|
|
65
|
+
- ``llm`` - LLM tracing category
|
|
66
|
+
- ``tool`` - Tool tracing category
|
|
67
|
+
- ``agent_data`` - Data operation tracing category
|
|
68
|
+
- ``message`` - Message/event tracing category
|
|
69
|
+
- ``judge`` - Evaluation/retry tracing category
|
|
70
|
+
|
|
71
|
+
Span Arguments and Aggregation
|
|
72
|
+
------------------------------
|
|
73
|
+
|
|
74
|
+
Spans carry their ``args`` (``trace_id``, ``step``, token counts, and so on) in the
|
|
75
|
+
trace, and ``span.update_args({...})`` adds values after the work finishes, such as
|
|
76
|
+
token usage from an LLM response.
|
|
77
|
+
|
|
78
|
+
DFTracer can aggregate short events into counters to keep traces small. An
|
|
79
|
+
aggregated event no longer carries its ``args``, so with the default aggregation a
|
|
80
|
+
short ``llm.call`` or ``tool.call`` loses its arguments, token counts included. To
|
|
81
|
+
keep agent spans intact, either turn aggregation off:
|
|
82
|
+
|
|
83
|
+
.. code-block:: bash
|
|
84
|
+
|
|
85
|
+
DFTRACER_ENABLE_AGGREGATION=0
|
|
86
|
+
|
|
87
|
+
or aggregate only the I/O events, with the ``SELECTIVE`` type and a rules file that
|
|
88
|
+
includes only POSIX and STDIO:
|
|
89
|
+
|
|
90
|
+
.. code-block:: bash
|
|
91
|
+
|
|
92
|
+
DFTRACER_ENABLE_AGGREGATION=1
|
|
93
|
+
DFTRACER_AGGREGATION_TYPE=SELECTIVE
|
|
94
|
+
DFTRACER_AGGREGATION_FILE=aggregation_rules.yaml
|
|
95
|
+
|
|
96
|
+
.. code-block:: yaml
|
|
97
|
+
|
|
98
|
+
inclusion:
|
|
99
|
+
- cat IN {POSIX,STDIO}
|
|
100
|
+
exclusion:
|
|
101
|
+
|
|
102
|
+
LangGraph Adapter
|
|
103
|
+
-----------------
|
|
104
|
+
|
|
105
|
+
Utilities for tracing LangGraph-style node and workflow invocation boundaries:
|
|
106
|
+
|
|
107
|
+
.. autofunction:: dftracer.python.get_or_init_trace_context
|
|
108
|
+
.. autofunction:: dftracer.python.traced_node
|
|
109
|
+
.. autofunction:: dftracer.python.trace_invoke
|
|
@@ -8,6 +8,7 @@ This section contains the complete API reference for pydftracer.
|
|
|
8
8
|
|
|
9
9
|
core
|
|
10
10
|
ai
|
|
11
|
+
agent
|
|
11
12
|
dynamo
|
|
12
13
|
env
|
|
13
14
|
|
|
@@ -35,6 +36,7 @@ AI/ML Support
|
|
|
35
36
|
~~~~~~~~~~~~~
|
|
36
37
|
|
|
37
38
|
- ``DFTracerAI`` - Base class for AI/ML tracing
|
|
39
|
+
- ``Agent`` - Base class for agent/workflow tracing
|
|
38
40
|
- ``Dynamo`` - PyTorch Dynamo integration class
|
|
39
41
|
- ``dynamo`` - Pre-configured Dynamo instance for tracing
|
|
40
42
|
- ``create_backend`` - Create a custom torch.compile backend with DFTracer
|
|
@@ -58,5 +60,6 @@ Modules
|
|
|
58
60
|
|
|
59
61
|
- :doc:`core` - Core tracing functionality (logger, common utilities)
|
|
60
62
|
- :doc:`ai` - AI/ML specific tracing features
|
|
63
|
+
- :doc:`agent` - Agent/workflow tracing features
|
|
61
64
|
- :doc:`dynamo` - PyTorch Dynamo integration
|
|
62
65
|
- :doc:`env` - Environment configuration and setup
|
|
@@ -15,6 +15,7 @@ Features
|
|
|
15
15
|
- **Type-Safe Decorators**: Fully type-checked with mypy, preserves function signatures
|
|
16
16
|
- **Function Decorators**: Simple ``@dft_fn`` decorator for tracing Python functions
|
|
17
17
|
- **AI/ML Support**: Specialized tracing for AI/ML workflows
|
|
18
|
+
- **Agent Workflow Support**: Structured tracing for agentic workflows
|
|
18
19
|
- **PyTorch Integration**: Capture PyTorch profiler events to DFTracer traces
|
|
19
20
|
- **PyTorch Dynamo Integration**: Wrapper of PyTorch's Dynamo
|
|
20
21
|
- **Automatic I/O Tracing**: Transparent tracing of I/O operations when enabled
|
|
@@ -125,7 +125,10 @@ ignore = [
|
|
|
125
125
|
"tests/*" = ["B011", "B023"]
|
|
126
126
|
"python/dftracer/python/logger.py" = ["E402", "F405"]
|
|
127
127
|
"python/dftracer/python/dbg/logger.py" = ["E402", "F405"]
|
|
128
|
+
"python/dftracer/python/dbg/agent.py" = ["E402"]
|
|
128
129
|
"python/dftracer/python/dbg/ai.py" = ["E402"]
|
|
130
|
+
"python/dftracer/python/agent.py" = ["E402"]
|
|
131
|
+
"python/dftracer/python/agent_init.py" = ["F405"]
|
|
129
132
|
"python/dftracer/python/ai.py" = ["E402"]
|
|
130
133
|
"python/dftracer/python/ai_common.py" = ["F405"]
|
|
131
134
|
"python/dftracer/python/ai_init.py" = ["F405"]
|
{pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/_version.py
RENAMED
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '2.0.
|
|
22
|
-
__version_tuple__ = version_tuple = (2, 0,
|
|
21
|
+
__version__ = version = '2.0.6.post2.dev0'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 0, 6, 'post2', 'dev0')
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g68307eab6'
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import dftracer.python.ai_common as ai_common
|
|
2
|
+
from dftracer.python.logger import dft_fn as dft_fn_orig
|
|
3
|
+
from dftracer.python.logger import dftracer as dftracer_orig
|
|
4
|
+
|
|
5
|
+
ai_common.dft_fn = dft_fn_orig # type: ignore[misc]
|
|
6
|
+
ai_common.dftracer = dftracer_orig # type: ignore[misc]
|
|
7
|
+
|
|
8
|
+
from dftracer.python.agent_common import *
|
|
9
|
+
from dftracer.python.agent_init import *
|
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
from typing import Any, Optional
|
|
2
|
+
|
|
3
|
+
from dftracer.python.ai_common import DFTracerAI
|
|
4
|
+
from dftracer.python.common import StringEnum, auto
|
|
5
|
+
|
|
6
|
+
ROOT_NAME = "agent_root"
|
|
7
|
+
ROOT_CAT = "agent_root"
|
|
8
|
+
|
|
9
|
+
TRACE_ID_KEY = "trace_id"
|
|
10
|
+
WORKFLOW_ID_KEY = "workflow_id"
|
|
11
|
+
RUN_ID_KEY = "run_id"
|
|
12
|
+
STEP_ID_KEY = "step_id"
|
|
13
|
+
AGENT_ID_KEY = "agent_id"
|
|
14
|
+
AGENT_ROLE_KEY = "agent_role"
|
|
15
|
+
SPAN_ID_KEY = "span_id"
|
|
16
|
+
PARENT_SPAN_ID_KEY = "parent_span_id"
|
|
17
|
+
TOOL_CALL_ID_KEY = "tool_call_id"
|
|
18
|
+
LLM_CALL_ID_KEY = "llm_call_id"
|
|
19
|
+
FRAMEWORK_KEY = "framework"
|
|
20
|
+
MODEL_NAME_KEY = "model_name"
|
|
21
|
+
MESSAGE_TYPE_KEY = "message_type"
|
|
22
|
+
LOGICAL_PATH_KEY = "logical_path"
|
|
23
|
+
PHYSICAL_PATH_KEY = "physical_path"
|
|
24
|
+
FORMAT_KEY = "format"
|
|
25
|
+
OPERATION_KIND_KEY = "operation_kind"
|
|
26
|
+
SUCCESS_KEY = "success"
|
|
27
|
+
ERROR_TYPE_KEY = "error_type"
|
|
28
|
+
|
|
29
|
+
# Token usage tracking keys for LLM calls
|
|
30
|
+
PROMPT_TOKENS_KEY = "prompt_tokens"
|
|
31
|
+
COMPLETION_TOKENS_KEY = "completion_tokens"
|
|
32
|
+
TOTAL_TOKENS_KEY = "total_tokens"
|
|
33
|
+
CONTEXT_SIZE_KEY = "context_size"
|
|
34
|
+
CONTEXT_WINDOW_KEY = "context_window"
|
|
35
|
+
CONTEXT_UTILIZATION_KEY = "context_utilization"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class AgentCategory(StringEnum):
|
|
39
|
+
WORKFLOW = auto()
|
|
40
|
+
STEP = auto()
|
|
41
|
+
LLM = auto()
|
|
42
|
+
TOOL = auto()
|
|
43
|
+
DATA = auto()
|
|
44
|
+
MESSAGE = auto()
|
|
45
|
+
JUDGE = auto()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class WorkflowEvent(StringEnum):
|
|
49
|
+
RUN = auto()
|
|
50
|
+
RESUME = auto()
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class AgentStepEvent(StringEnum):
|
|
54
|
+
PLAN = auto()
|
|
55
|
+
ACT = auto()
|
|
56
|
+
OBSERVE = auto()
|
|
57
|
+
REFLECT = auto()
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class LLMEvent(StringEnum):
|
|
61
|
+
CALL = auto()
|
|
62
|
+
STREAM = auto()
|
|
63
|
+
PARSE = auto()
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class ToolEvent(StringEnum):
|
|
67
|
+
CALL = auto()
|
|
68
|
+
RESULT = auto()
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class AgentDataEvent(StringEnum):
|
|
72
|
+
LOAD = auto()
|
|
73
|
+
SAVE = auto()
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class MessageEvent(StringEnum):
|
|
77
|
+
SEND = auto()
|
|
78
|
+
RECEIVE = auto()
|
|
79
|
+
STREAM = auto()
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class JudgeEvent(StringEnum):
|
|
83
|
+
EVALUATE = auto()
|
|
84
|
+
RETRY = auto()
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class Workflow(DFTracerAI):
|
|
88
|
+
run: DFTracerAI
|
|
89
|
+
resume: DFTracerAI
|
|
90
|
+
|
|
91
|
+
def __init__(
|
|
92
|
+
self,
|
|
93
|
+
epoch: Optional[int] = None,
|
|
94
|
+
step: Optional[int] = None,
|
|
95
|
+
image_idx: Optional[int] = None,
|
|
96
|
+
image_size: Optional[Any] = None,
|
|
97
|
+
enable: bool = True,
|
|
98
|
+
):
|
|
99
|
+
super().__init__(
|
|
100
|
+
cat=AgentCategory.WORKFLOW,
|
|
101
|
+
name=AgentCategory.WORKFLOW,
|
|
102
|
+
epoch=epoch,
|
|
103
|
+
step=step,
|
|
104
|
+
image_idx=image_idx,
|
|
105
|
+
image_size=image_size,
|
|
106
|
+
enable=enable,
|
|
107
|
+
)
|
|
108
|
+
self.create_children(
|
|
109
|
+
{
|
|
110
|
+
"run": WorkflowEvent.RUN,
|
|
111
|
+
"resume": WorkflowEvent.RESUME,
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class AgentStep(DFTracerAI):
|
|
117
|
+
plan: DFTracerAI
|
|
118
|
+
act: DFTracerAI
|
|
119
|
+
observe: DFTracerAI
|
|
120
|
+
reflect: DFTracerAI
|
|
121
|
+
|
|
122
|
+
def __init__(
|
|
123
|
+
self,
|
|
124
|
+
epoch: Optional[int] = None,
|
|
125
|
+
step: Optional[int] = None,
|
|
126
|
+
image_idx: Optional[int] = None,
|
|
127
|
+
image_size: Optional[Any] = None,
|
|
128
|
+
enable: bool = True,
|
|
129
|
+
):
|
|
130
|
+
super().__init__(
|
|
131
|
+
cat=AgentCategory.STEP,
|
|
132
|
+
name=AgentCategory.STEP,
|
|
133
|
+
epoch=epoch,
|
|
134
|
+
step=step,
|
|
135
|
+
image_idx=image_idx,
|
|
136
|
+
image_size=image_size,
|
|
137
|
+
enable=enable,
|
|
138
|
+
)
|
|
139
|
+
self.create_children(
|
|
140
|
+
{
|
|
141
|
+
"plan": AgentStepEvent.PLAN,
|
|
142
|
+
"act": AgentStepEvent.ACT,
|
|
143
|
+
"observe": AgentStepEvent.OBSERVE,
|
|
144
|
+
"reflect": AgentStepEvent.REFLECT,
|
|
145
|
+
}
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class LLM(DFTracerAI):
|
|
150
|
+
call: DFTracerAI
|
|
151
|
+
stream: DFTracerAI
|
|
152
|
+
parse: DFTracerAI
|
|
153
|
+
|
|
154
|
+
def __init__(
|
|
155
|
+
self,
|
|
156
|
+
epoch: Optional[int] = None,
|
|
157
|
+
step: Optional[int] = None,
|
|
158
|
+
image_idx: Optional[int] = None,
|
|
159
|
+
image_size: Optional[Any] = None,
|
|
160
|
+
enable: bool = True,
|
|
161
|
+
):
|
|
162
|
+
super().__init__(
|
|
163
|
+
cat=AgentCategory.LLM,
|
|
164
|
+
name=AgentCategory.LLM,
|
|
165
|
+
epoch=epoch,
|
|
166
|
+
step=step,
|
|
167
|
+
image_idx=image_idx,
|
|
168
|
+
image_size=image_size,
|
|
169
|
+
enable=enable,
|
|
170
|
+
)
|
|
171
|
+
self.create_children(
|
|
172
|
+
{
|
|
173
|
+
"call": LLMEvent.CALL,
|
|
174
|
+
"stream": LLMEvent.STREAM,
|
|
175
|
+
"parse": LLMEvent.PARSE,
|
|
176
|
+
}
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
class Tool(DFTracerAI):
|
|
181
|
+
call: DFTracerAI
|
|
182
|
+
result: DFTracerAI
|
|
183
|
+
|
|
184
|
+
def __init__(
|
|
185
|
+
self,
|
|
186
|
+
epoch: Optional[int] = None,
|
|
187
|
+
step: Optional[int] = None,
|
|
188
|
+
image_idx: Optional[int] = None,
|
|
189
|
+
image_size: Optional[Any] = None,
|
|
190
|
+
enable: bool = True,
|
|
191
|
+
):
|
|
192
|
+
super().__init__(
|
|
193
|
+
cat=AgentCategory.TOOL,
|
|
194
|
+
name=AgentCategory.TOOL,
|
|
195
|
+
epoch=epoch,
|
|
196
|
+
step=step,
|
|
197
|
+
image_idx=image_idx,
|
|
198
|
+
image_size=image_size,
|
|
199
|
+
enable=enable,
|
|
200
|
+
)
|
|
201
|
+
self.create_children(
|
|
202
|
+
{
|
|
203
|
+
"call": ToolEvent.CALL,
|
|
204
|
+
"result": ToolEvent.RESULT,
|
|
205
|
+
}
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class AgentData(DFTracerAI):
|
|
210
|
+
load: DFTracerAI
|
|
211
|
+
save: DFTracerAI
|
|
212
|
+
|
|
213
|
+
def __init__(
|
|
214
|
+
self,
|
|
215
|
+
epoch: Optional[int] = None,
|
|
216
|
+
step: Optional[int] = None,
|
|
217
|
+
image_idx: Optional[int] = None,
|
|
218
|
+
image_size: Optional[Any] = None,
|
|
219
|
+
enable: bool = True,
|
|
220
|
+
):
|
|
221
|
+
super().__init__(
|
|
222
|
+
cat=AgentCategory.DATA,
|
|
223
|
+
name=AgentCategory.DATA,
|
|
224
|
+
epoch=epoch,
|
|
225
|
+
step=step,
|
|
226
|
+
image_idx=image_idx,
|
|
227
|
+
image_size=image_size,
|
|
228
|
+
enable=enable,
|
|
229
|
+
)
|
|
230
|
+
self.create_children(
|
|
231
|
+
{
|
|
232
|
+
"load": AgentDataEvent.LOAD,
|
|
233
|
+
"save": AgentDataEvent.SAVE,
|
|
234
|
+
}
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
class Message(DFTracerAI):
|
|
239
|
+
send: DFTracerAI
|
|
240
|
+
receive: DFTracerAI
|
|
241
|
+
stream: DFTracerAI
|
|
242
|
+
|
|
243
|
+
def __init__(
|
|
244
|
+
self,
|
|
245
|
+
epoch: Optional[int] = None,
|
|
246
|
+
step: Optional[int] = None,
|
|
247
|
+
image_idx: Optional[int] = None,
|
|
248
|
+
image_size: Optional[Any] = None,
|
|
249
|
+
enable: bool = True,
|
|
250
|
+
):
|
|
251
|
+
super().__init__(
|
|
252
|
+
cat=AgentCategory.MESSAGE,
|
|
253
|
+
name=AgentCategory.MESSAGE,
|
|
254
|
+
epoch=epoch,
|
|
255
|
+
step=step,
|
|
256
|
+
image_idx=image_idx,
|
|
257
|
+
image_size=image_size,
|
|
258
|
+
enable=enable,
|
|
259
|
+
)
|
|
260
|
+
self.create_children(
|
|
261
|
+
{
|
|
262
|
+
"send": MessageEvent.SEND,
|
|
263
|
+
"receive": MessageEvent.RECEIVE,
|
|
264
|
+
"stream": MessageEvent.STREAM,
|
|
265
|
+
}
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
class Judge(DFTracerAI):
|
|
270
|
+
evaluate: DFTracerAI
|
|
271
|
+
retry: DFTracerAI
|
|
272
|
+
|
|
273
|
+
def __init__(
|
|
274
|
+
self,
|
|
275
|
+
epoch: Optional[int] = None,
|
|
276
|
+
step: Optional[int] = None,
|
|
277
|
+
image_idx: Optional[int] = None,
|
|
278
|
+
image_size: Optional[Any] = None,
|
|
279
|
+
enable: bool = True,
|
|
280
|
+
):
|
|
281
|
+
super().__init__(
|
|
282
|
+
cat=AgentCategory.JUDGE,
|
|
283
|
+
name=AgentCategory.JUDGE,
|
|
284
|
+
epoch=epoch,
|
|
285
|
+
step=step,
|
|
286
|
+
image_idx=image_idx,
|
|
287
|
+
image_size=image_size,
|
|
288
|
+
enable=enable,
|
|
289
|
+
)
|
|
290
|
+
self.create_children(
|
|
291
|
+
{
|
|
292
|
+
"evaluate": JudgeEvent.EVALUATE,
|
|
293
|
+
"retry": JudgeEvent.RETRY,
|
|
294
|
+
}
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
# fmt: off
|
|
299
|
+
class Agent(DFTracerAI):
|
|
300
|
+
workflow: Workflow
|
|
301
|
+
step: AgentStep
|
|
302
|
+
llm: LLM
|
|
303
|
+
tool: Tool
|
|
304
|
+
data: AgentData
|
|
305
|
+
message: Message
|
|
306
|
+
judge: Judge
|
|
307
|
+
|
|
308
|
+
def __init__(
|
|
309
|
+
self,
|
|
310
|
+
epoch: Optional[int] = None,
|
|
311
|
+
step: Optional[int] = None,
|
|
312
|
+
image_idx: Optional[int] = None,
|
|
313
|
+
image_size: Optional[Any] = None,
|
|
314
|
+
enable: bool = True,
|
|
315
|
+
):
|
|
316
|
+
super().__init__(cat=ROOT_CAT, name=ROOT_NAME, epoch=epoch, step=step, image_idx=image_idx, image_size=image_size, enable=enable)
|
|
317
|
+
self.workflow = Workflow(epoch=epoch, step=step, image_idx=image_idx, image_size=image_size, enable=enable)
|
|
318
|
+
self.step = AgentStep(epoch=epoch, step=step, image_idx=image_idx, image_size=image_size, enable=enable)
|
|
319
|
+
self.llm = LLM(epoch=epoch, step=step, image_idx=image_idx, image_size=image_size, enable=enable)
|
|
320
|
+
self.tool = Tool(epoch=epoch, step=step, image_idx=image_idx, image_size=image_size, enable=enable)
|
|
321
|
+
self.data = AgentData(epoch=epoch, step=step, image_idx=image_idx, image_size=image_size, enable=enable)
|
|
322
|
+
self.message = Message(epoch=epoch, step=step, image_idx=image_idx, image_size=image_size, enable=enable)
|
|
323
|
+
self.judge = Judge(epoch=epoch, step=step, image_idx=image_idx, image_size=image_size, enable=enable)
|
|
324
|
+
|
|
325
|
+
self._children = {
|
|
326
|
+
"workflow": self.workflow,
|
|
327
|
+
"step": self.step,
|
|
328
|
+
"llm": self.llm,
|
|
329
|
+
"tool": self.tool,
|
|
330
|
+
"data": self.data,
|
|
331
|
+
"message": self.message,
|
|
332
|
+
"judge": self.judge,
|
|
333
|
+
}
|
|
334
|
+
# fmt: on
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
__all__ = [
|
|
338
|
+
"ROOT_NAME",
|
|
339
|
+
"ROOT_CAT",
|
|
340
|
+
"TRACE_ID_KEY",
|
|
341
|
+
"WORKFLOW_ID_KEY",
|
|
342
|
+
"RUN_ID_KEY",
|
|
343
|
+
"STEP_ID_KEY",
|
|
344
|
+
"AGENT_ID_KEY",
|
|
345
|
+
"AGENT_ROLE_KEY",
|
|
346
|
+
"SPAN_ID_KEY",
|
|
347
|
+
"PARENT_SPAN_ID_KEY",
|
|
348
|
+
"TOOL_CALL_ID_KEY",
|
|
349
|
+
"LLM_CALL_ID_KEY",
|
|
350
|
+
"FRAMEWORK_KEY",
|
|
351
|
+
"MODEL_NAME_KEY",
|
|
352
|
+
"MESSAGE_TYPE_KEY",
|
|
353
|
+
"LOGICAL_PATH_KEY",
|
|
354
|
+
"PHYSICAL_PATH_KEY",
|
|
355
|
+
"FORMAT_KEY",
|
|
356
|
+
"OPERATION_KIND_KEY",
|
|
357
|
+
"SUCCESS_KEY",
|
|
358
|
+
"ERROR_TYPE_KEY",
|
|
359
|
+
"PROMPT_TOKENS_KEY",
|
|
360
|
+
"COMPLETION_TOKENS_KEY",
|
|
361
|
+
"TOTAL_TOKENS_KEY",
|
|
362
|
+
"CONTEXT_SIZE_KEY",
|
|
363
|
+
"CONTEXT_WINDOW_KEY",
|
|
364
|
+
"CONTEXT_UTILIZATION_KEY",
|
|
365
|
+
"AgentCategory",
|
|
366
|
+
"WorkflowEvent",
|
|
367
|
+
"AgentStepEvent",
|
|
368
|
+
"LLMEvent",
|
|
369
|
+
"ToolEvent",
|
|
370
|
+
"AgentDataEvent",
|
|
371
|
+
"MessageEvent",
|
|
372
|
+
"JudgeEvent",
|
|
373
|
+
"Workflow",
|
|
374
|
+
"AgentStep",
|
|
375
|
+
"LLM",
|
|
376
|
+
"Tool",
|
|
377
|
+
"AgentData",
|
|
378
|
+
"Message",
|
|
379
|
+
"Judge",
|
|
380
|
+
"Agent",
|
|
381
|
+
]
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from dftracer.python.agent_common import *
|
|
2
|
+
|
|
3
|
+
agent = Agent()
|
|
4
|
+
workflow = agent.workflow
|
|
5
|
+
agent_step = agent.step
|
|
6
|
+
llm = agent.llm
|
|
7
|
+
tool = agent.tool
|
|
8
|
+
agent_data = agent.data
|
|
9
|
+
message = agent.message
|
|
10
|
+
judge = agent.judge
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"ROOT_NAME",
|
|
14
|
+
"ROOT_CAT",
|
|
15
|
+
"TRACE_ID_KEY",
|
|
16
|
+
"WORKFLOW_ID_KEY",
|
|
17
|
+
"RUN_ID_KEY",
|
|
18
|
+
"STEP_ID_KEY",
|
|
19
|
+
"AGENT_ID_KEY",
|
|
20
|
+
"AGENT_ROLE_KEY",
|
|
21
|
+
"SPAN_ID_KEY",
|
|
22
|
+
"PARENT_SPAN_ID_KEY",
|
|
23
|
+
"TOOL_CALL_ID_KEY",
|
|
24
|
+
"LLM_CALL_ID_KEY",
|
|
25
|
+
"FRAMEWORK_KEY",
|
|
26
|
+
"MODEL_NAME_KEY",
|
|
27
|
+
"MESSAGE_TYPE_KEY",
|
|
28
|
+
"LOGICAL_PATH_KEY",
|
|
29
|
+
"PHYSICAL_PATH_KEY",
|
|
30
|
+
"FORMAT_KEY",
|
|
31
|
+
"OPERATION_KIND_KEY",
|
|
32
|
+
"SUCCESS_KEY",
|
|
33
|
+
"ERROR_TYPE_KEY",
|
|
34
|
+
"PROMPT_TOKENS_KEY",
|
|
35
|
+
"COMPLETION_TOKENS_KEY",
|
|
36
|
+
"TOTAL_TOKENS_KEY",
|
|
37
|
+
"CONTEXT_SIZE_KEY",
|
|
38
|
+
"CONTEXT_WINDOW_KEY",
|
|
39
|
+
"CONTEXT_UTILIZATION_KEY",
|
|
40
|
+
"AgentCategory",
|
|
41
|
+
"WorkflowEvent",
|
|
42
|
+
"AgentStepEvent",
|
|
43
|
+
"LLMEvent",
|
|
44
|
+
"ToolEvent",
|
|
45
|
+
"AgentDataEvent",
|
|
46
|
+
"MessageEvent",
|
|
47
|
+
"JudgeEvent",
|
|
48
|
+
"agent",
|
|
49
|
+
"workflow",
|
|
50
|
+
"agent_step",
|
|
51
|
+
"llm",
|
|
52
|
+
"tool",
|
|
53
|
+
"agent_data",
|
|
54
|
+
"message",
|
|
55
|
+
"judge",
|
|
56
|
+
]
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import uuid
|
|
2
|
+
from typing import Any, Callable, Dict, Mapping, MutableMapping, Optional
|
|
3
|
+
|
|
4
|
+
from dftracer.python.agent_common import (
|
|
5
|
+
AGENT_ID_KEY,
|
|
6
|
+
AGENT_ROLE_KEY,
|
|
7
|
+
FRAMEWORK_KEY,
|
|
8
|
+
OPERATION_KIND_KEY,
|
|
9
|
+
PARENT_SPAN_ID_KEY,
|
|
10
|
+
RUN_ID_KEY,
|
|
11
|
+
SPAN_ID_KEY,
|
|
12
|
+
STEP_ID_KEY,
|
|
13
|
+
TRACE_ID_KEY,
|
|
14
|
+
WORKFLOW_ID_KEY,
|
|
15
|
+
)
|
|
16
|
+
from dftracer.python.agent_init import agent_step, workflow
|
|
17
|
+
from dftracer.python.ai_common import DFTracerAI
|
|
18
|
+
from dftracer.python.common import P, R
|
|
19
|
+
|
|
20
|
+
DEFAULT_FRAMEWORK_NAME = "langgraph"
|
|
21
|
+
DEFAULT_WORKFLOW_EVENT_NAME = "langgraph.invoke"
|
|
22
|
+
DEFAULT_NODE_OPERATION_KIND = "node"
|
|
23
|
+
DEFAULT_WORKFLOW_OPERATION_KIND = "workflow"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _new_id() -> str:
|
|
27
|
+
return uuid.uuid4().hex
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _extract_thread_id(config: Optional[Mapping[str, Any]]) -> Optional[str]:
|
|
31
|
+
if not config:
|
|
32
|
+
return None
|
|
33
|
+
configurable = config.get("configurable")
|
|
34
|
+
if not isinstance(configurable, Mapping):
|
|
35
|
+
return None
|
|
36
|
+
thread_id = configurable.get("thread_id")
|
|
37
|
+
if thread_id is None:
|
|
38
|
+
return None
|
|
39
|
+
return str(thread_id)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _prune_none_values(args: Dict[str, Any]) -> Dict[str, Any]:
|
|
43
|
+
return {k: v for k, v in args.items() if v is not None}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _get_step_event_tracer(step_event: str) -> DFTracerAI:
|
|
47
|
+
tracer: Optional[DFTracerAI] = getattr(agent_step, step_event, None)
|
|
48
|
+
if tracer is None:
|
|
49
|
+
valid_events = ", ".join(sorted(agent_step._children.keys()))
|
|
50
|
+
raise ValueError(
|
|
51
|
+
f"Unknown step_event '{step_event}'. Valid values: {valid_events}"
|
|
52
|
+
)
|
|
53
|
+
return tracer
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def get_or_init_trace_context(
|
|
57
|
+
state: Optional[Mapping[str, Any]] = None,
|
|
58
|
+
config: Optional[Mapping[str, Any]] = None,
|
|
59
|
+
) -> Dict[str, Optional[str]]:
|
|
60
|
+
state = state or {}
|
|
61
|
+
|
|
62
|
+
trace_id = state.get(TRACE_ID_KEY)
|
|
63
|
+
if trace_id is not None:
|
|
64
|
+
trace_id = str(trace_id)
|
|
65
|
+
if not trace_id:
|
|
66
|
+
trace_id = _new_id()
|
|
67
|
+
|
|
68
|
+
workflow_id = state.get(WORKFLOW_ID_KEY)
|
|
69
|
+
if workflow_id is not None:
|
|
70
|
+
workflow_id = str(workflow_id)
|
|
71
|
+
if not workflow_id:
|
|
72
|
+
workflow_id = _extract_thread_id(config) or _new_id()
|
|
73
|
+
|
|
74
|
+
parent_span_id = state.get(PARENT_SPAN_ID_KEY)
|
|
75
|
+
if parent_span_id is not None:
|
|
76
|
+
parent_span_id = str(parent_span_id)
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
TRACE_ID_KEY: trace_id,
|
|
80
|
+
WORKFLOW_ID_KEY: workflow_id,
|
|
81
|
+
PARENT_SPAN_ID_KEY: parent_span_id,
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _merge_trace_updates(
|
|
86
|
+
updates: MutableMapping[str, Any], trace_id: str, workflow_id: str, span_id: str
|
|
87
|
+
) -> MutableMapping[str, Any]:
|
|
88
|
+
updates.setdefault(TRACE_ID_KEY, trace_id)
|
|
89
|
+
updates.setdefault(WORKFLOW_ID_KEY, workflow_id)
|
|
90
|
+
updates.setdefault(PARENT_SPAN_ID_KEY, span_id)
|
|
91
|
+
return updates
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def traced_node(
|
|
95
|
+
node_name: str,
|
|
96
|
+
*,
|
|
97
|
+
agent_role: str = "",
|
|
98
|
+
step_event: str = "act",
|
|
99
|
+
framework: str = DEFAULT_FRAMEWORK_NAME,
|
|
100
|
+
) -> Callable[[Callable[P, R]], Callable[P, R]]:
|
|
101
|
+
tracer = _get_step_event_tracer(step_event)
|
|
102
|
+
|
|
103
|
+
def _decorator(fn: Callable[P, R]) -> Callable[P, R]:
|
|
104
|
+
def _wrapped(*args: P.args, **kwargs: P.kwargs) -> R:
|
|
105
|
+
state: Optional[Mapping[str, Any]] = None
|
|
106
|
+
kw_state = kwargs.get("state")
|
|
107
|
+
if len(args) > 0 and isinstance(args[0], Mapping):
|
|
108
|
+
state = args[0]
|
|
109
|
+
elif isinstance(kw_state, Mapping):
|
|
110
|
+
state = kw_state
|
|
111
|
+
|
|
112
|
+
config: Optional[Mapping[str, Any]] = None
|
|
113
|
+
kw_config = kwargs.get("config")
|
|
114
|
+
if len(args) > 1 and isinstance(args[1], Mapping):
|
|
115
|
+
config = args[1]
|
|
116
|
+
elif isinstance(kw_config, Mapping):
|
|
117
|
+
config = kw_config
|
|
118
|
+
|
|
119
|
+
ctx = get_or_init_trace_context(state=state, config=config)
|
|
120
|
+
span_id = _new_id()
|
|
121
|
+
event_args = _prune_none_values(
|
|
122
|
+
{
|
|
123
|
+
TRACE_ID_KEY: ctx[TRACE_ID_KEY],
|
|
124
|
+
WORKFLOW_ID_KEY: ctx[WORKFLOW_ID_KEY],
|
|
125
|
+
SPAN_ID_KEY: span_id,
|
|
126
|
+
STEP_ID_KEY: span_id,
|
|
127
|
+
PARENT_SPAN_ID_KEY: ctx[PARENT_SPAN_ID_KEY],
|
|
128
|
+
AGENT_ID_KEY: node_name,
|
|
129
|
+
AGENT_ROLE_KEY: agent_role or None,
|
|
130
|
+
FRAMEWORK_KEY: framework,
|
|
131
|
+
OPERATION_KIND_KEY: DEFAULT_NODE_OPERATION_KIND,
|
|
132
|
+
}
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
with tracer(args=event_args):
|
|
136
|
+
result = fn(*args, **kwargs)
|
|
137
|
+
|
|
138
|
+
if result is None:
|
|
139
|
+
updates: MutableMapping[str, Any] = {}
|
|
140
|
+
merged = _merge_trace_updates(
|
|
141
|
+
updates=updates,
|
|
142
|
+
trace_id=str(ctx[TRACE_ID_KEY]),
|
|
143
|
+
workflow_id=str(ctx[WORKFLOW_ID_KEY]),
|
|
144
|
+
span_id=span_id,
|
|
145
|
+
)
|
|
146
|
+
return merged # type: ignore[return-value]
|
|
147
|
+
|
|
148
|
+
if isinstance(result, Mapping):
|
|
149
|
+
updates = dict(result)
|
|
150
|
+
merged = _merge_trace_updates(
|
|
151
|
+
updates=updates,
|
|
152
|
+
trace_id=str(ctx[TRACE_ID_KEY]),
|
|
153
|
+
workflow_id=str(ctx[WORKFLOW_ID_KEY]),
|
|
154
|
+
span_id=span_id,
|
|
155
|
+
)
|
|
156
|
+
return merged # type: ignore[return-value]
|
|
157
|
+
|
|
158
|
+
return result
|
|
159
|
+
|
|
160
|
+
return _wrapped
|
|
161
|
+
|
|
162
|
+
return _decorator
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def trace_invoke(
|
|
166
|
+
app: Any,
|
|
167
|
+
state: Any,
|
|
168
|
+
config: Optional[Mapping[str, Any]] = None,
|
|
169
|
+
*,
|
|
170
|
+
workflow_name: str = DEFAULT_WORKFLOW_EVENT_NAME,
|
|
171
|
+
framework: str = DEFAULT_FRAMEWORK_NAME,
|
|
172
|
+
run_id: Optional[str] = None,
|
|
173
|
+
) -> Any:
|
|
174
|
+
if not hasattr(app, "invoke"):
|
|
175
|
+
raise AttributeError("Expected app to have an 'invoke' method")
|
|
176
|
+
|
|
177
|
+
state_mapping = state if isinstance(state, Mapping) else None
|
|
178
|
+
ctx = get_or_init_trace_context(state=state_mapping, config=config)
|
|
179
|
+
run_id = run_id or _new_id()
|
|
180
|
+
span_id = _new_id()
|
|
181
|
+
|
|
182
|
+
event_args = _prune_none_values(
|
|
183
|
+
{
|
|
184
|
+
TRACE_ID_KEY: ctx[TRACE_ID_KEY],
|
|
185
|
+
WORKFLOW_ID_KEY: ctx[WORKFLOW_ID_KEY],
|
|
186
|
+
RUN_ID_KEY: run_id,
|
|
187
|
+
SPAN_ID_KEY: span_id,
|
|
188
|
+
PARENT_SPAN_ID_KEY: ctx[PARENT_SPAN_ID_KEY],
|
|
189
|
+
FRAMEWORK_KEY: framework,
|
|
190
|
+
OPERATION_KIND_KEY: DEFAULT_WORKFLOW_OPERATION_KIND,
|
|
191
|
+
}
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
workflow_tracer = (
|
|
195
|
+
workflow.run.derive(workflow_name) if workflow_name else workflow.run
|
|
196
|
+
)
|
|
197
|
+
with workflow_tracer(args=event_args):
|
|
198
|
+
if config is None:
|
|
199
|
+
return app.invoke(state)
|
|
200
|
+
return app.invoke(state, config=config)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
__all__ = [
|
|
204
|
+
"DEFAULT_FRAMEWORK_NAME",
|
|
205
|
+
"DEFAULT_WORKFLOW_EVENT_NAME",
|
|
206
|
+
"DEFAULT_NODE_OPERATION_KIND",
|
|
207
|
+
"DEFAULT_WORKFLOW_OPERATION_KIND",
|
|
208
|
+
"get_or_init_trace_context",
|
|
209
|
+
"traced_node",
|
|
210
|
+
"trace_invoke",
|
|
211
|
+
]
|
{pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/ai_common.py
RENAMED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import functools
|
|
2
|
-
import
|
|
3
|
-
from typing import Any, Callable, Dict, Iterator, List, Optional, overload
|
|
2
|
+
from typing import Any, Callable, Dict, Iterator, Optional, overload
|
|
4
3
|
|
|
5
4
|
from dftracer.python.common import *
|
|
6
5
|
from dftracer.python.env import *
|
|
@@ -8,34 +7,6 @@ from dftracer.python.env import *
|
|
|
8
7
|
dft_fn = None # type: ignore
|
|
9
8
|
dftracer = None # type: ignore
|
|
10
9
|
|
|
11
|
-
if sys.version_info >= (3, 11):
|
|
12
|
-
from enum import StrEnum as StringEnum
|
|
13
|
-
from enum import auto
|
|
14
|
-
# StrEnum in 3.11 already lower-case
|
|
15
|
-
else:
|
|
16
|
-
from enum import Enum, auto
|
|
17
|
-
|
|
18
|
-
# MIT License: https://github.com/irgeek/StrEnum/blob/master/strenum/__init__.py
|
|
19
|
-
class StringEnum(str, Enum):
|
|
20
|
-
# this is a specific version that will lowercase the values
|
|
21
|
-
|
|
22
|
-
def __new__(cls, value: Any, *args: Any, **kwargs: Any) -> "StringEnum":
|
|
23
|
-
if not isinstance(value, (str, auto)):
|
|
24
|
-
raise TypeError( # pragma: no cover
|
|
25
|
-
f"Values of StrEnums must be strings: {value!r} is a {type(value)}"
|
|
26
|
-
)
|
|
27
|
-
return super().__new__(cls, value, *args, **kwargs)
|
|
28
|
-
|
|
29
|
-
def __str__(self) -> str:
|
|
30
|
-
return str(self.value)
|
|
31
|
-
|
|
32
|
-
@staticmethod
|
|
33
|
-
def _generate_next_value_(
|
|
34
|
-
name: str, start: int, count: int, last_values: List[Any]
|
|
35
|
-
) -> str:
|
|
36
|
-
return name.lower()
|
|
37
|
-
|
|
38
|
-
|
|
39
10
|
ITER_COUNT_NAME = "count"
|
|
40
11
|
INIT_NAME = "init"
|
|
41
12
|
BLOCK_NAME = "block"
|
|
@@ -123,44 +94,16 @@ class _DFTracerAI:
|
|
|
123
94
|
image_size: Optional[Any] = None,
|
|
124
95
|
args: Optional[Dict[str, Any]] = None,
|
|
125
96
|
) -> Union[Callable[P, R], "DFTracerAI"]:
|
|
126
|
-
if epoch is not None:
|
|
127
|
-
self.profiler._arguments_int["epoch"] = TagValue(
|
|
128
|
-
epoch, TagDType.INT, TagType.KEY
|
|
129
|
-
).value()
|
|
130
|
-
if step is not None:
|
|
131
|
-
self.profiler._arguments_int["step"] = TagValue(
|
|
132
|
-
step, TagDType.INT, TagType.KEY
|
|
133
|
-
).value()
|
|
134
|
-
if image_idx is not None:
|
|
135
|
-
self.profiler._arguments_int["image_idx"] = TagValue(
|
|
136
|
-
image_idx, TagDType.INT, TagType.KEY
|
|
137
|
-
).value()
|
|
138
|
-
if image_size is not None:
|
|
139
|
-
self.profiler._arguments_float["image_size"] = TagValue(
|
|
140
|
-
image_size, TagDType.FLOAT, TagType.KEY
|
|
141
|
-
).value()
|
|
142
|
-
args = args or {}
|
|
143
|
-
for key, value in args.items():
|
|
144
|
-
if isinstance(value, TagValue):
|
|
145
|
-
new_value = value._value
|
|
146
|
-
else:
|
|
147
|
-
new_value = value
|
|
148
|
-
if isinstance(new_value, int):
|
|
149
|
-
self.profiler._arguments_int[key] = TagValue(
|
|
150
|
-
new_value, TagDType.INT, TagType.KEY
|
|
151
|
-
).value()
|
|
152
|
-
elif isinstance(new_value, float):
|
|
153
|
-
self.profiler._arguments_float[key] = TagValue(
|
|
154
|
-
new_value, TagDType.FLOAT, TagType.KEY
|
|
155
|
-
).value()
|
|
156
|
-
else:
|
|
157
|
-
self.profiler._arguments_string[key] = TagValue(
|
|
158
|
-
str(new_value), TagDType.STRING, TagType.KEY
|
|
159
|
-
).value()
|
|
160
|
-
|
|
161
97
|
is_enabled = self.profiler._enable if enable is None else enable
|
|
162
98
|
|
|
163
99
|
if fn:
|
|
100
|
+
self.update(
|
|
101
|
+
epoch=epoch,
|
|
102
|
+
step=step,
|
|
103
|
+
image_idx=image_idx,
|
|
104
|
+
image_size=image_size,
|
|
105
|
+
args=args,
|
|
106
|
+
)
|
|
164
107
|
|
|
165
108
|
def _decorator(f: Callable[P, R]) -> Callable[P, R]:
|
|
166
109
|
@functools.wraps(f)
|
|
@@ -174,15 +117,25 @@ class _DFTracerAI:
|
|
|
174
117
|
|
|
175
118
|
return _decorator(fn)
|
|
176
119
|
else:
|
|
177
|
-
|
|
120
|
+
tracer = DFTracerAI(
|
|
178
121
|
cat=self.profiler._cat,
|
|
179
122
|
name=self.profiler._name,
|
|
123
|
+
enable=is_enabled,
|
|
124
|
+
)
|
|
125
|
+
if DFTRACER_ENABLE and tracer.profiler._enable:
|
|
126
|
+
tracer.profiler._arguments_int = dict(self.profiler._arguments_int)
|
|
127
|
+
tracer.profiler._arguments_float = dict(self.profiler._arguments_float)
|
|
128
|
+
tracer.profiler._arguments_string = dict(
|
|
129
|
+
self.profiler._arguments_string
|
|
130
|
+
)
|
|
131
|
+
tracer.update(
|
|
180
132
|
epoch=epoch,
|
|
181
133
|
step=step,
|
|
182
134
|
image_idx=image_idx,
|
|
183
135
|
image_size=image_size,
|
|
184
|
-
|
|
136
|
+
args=args,
|
|
185
137
|
)
|
|
138
|
+
return tracer
|
|
186
139
|
|
|
187
140
|
def __enter__(self) -> "_DFTracerAI":
|
|
188
141
|
self.profiler.__enter__()
|
|
@@ -285,6 +238,46 @@ class _DFTracerAI:
|
|
|
285
238
|
).value()
|
|
286
239
|
return self
|
|
287
240
|
|
|
241
|
+
def update_args(self, args: Dict[str, Any]) -> "_DFTracerAI":
|
|
242
|
+
"""Update event arguments during span execution (e.g., token usage from LLM response).
|
|
243
|
+
|
|
244
|
+
This method allows adding or updating args after __enter__ but before __exit__,
|
|
245
|
+
which is useful for capturing metrics from API responses (like token counts).
|
|
246
|
+
|
|
247
|
+
Args:
|
|
248
|
+
args: Dictionary of argument names to values. Int, float, and str types are supported.
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
self for chaining.
|
|
252
|
+
|
|
253
|
+
Example:
|
|
254
|
+
with llm.call(args={"model": "gpt-4"}) as span:
|
|
255
|
+
response = api.call()
|
|
256
|
+
span.update_args({
|
|
257
|
+
"prompt_tokens": response["usage"]["prompt_tokens"],
|
|
258
|
+
"completion_tokens": response["usage"]["completion_tokens"],
|
|
259
|
+
})
|
|
260
|
+
"""
|
|
261
|
+
if DFTRACER_ENABLE and self.profiler._enable:
|
|
262
|
+
for key, value in args.items():
|
|
263
|
+
if isinstance(value, TagValue):
|
|
264
|
+
new_value = value._value
|
|
265
|
+
else:
|
|
266
|
+
new_value = value
|
|
267
|
+
if isinstance(new_value, int):
|
|
268
|
+
self.profiler._arguments_int[key] = TagValue(
|
|
269
|
+
new_value, TagDType.INT, TagType.KEY
|
|
270
|
+
).value()
|
|
271
|
+
elif isinstance(new_value, float):
|
|
272
|
+
self.profiler._arguments_float[key] = TagValue(
|
|
273
|
+
new_value, TagDType.FLOAT, TagType.KEY
|
|
274
|
+
).value()
|
|
275
|
+
else:
|
|
276
|
+
self.profiler._arguments_string[key] = TagValue(
|
|
277
|
+
str(new_value), TagDType.STRING, TagType.KEY
|
|
278
|
+
).value()
|
|
279
|
+
return self
|
|
280
|
+
|
|
288
281
|
def iter(
|
|
289
282
|
self,
|
|
290
283
|
iterator: Iterator,
|
{pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/common.py
RENAMED
|
@@ -4,7 +4,7 @@ import os
|
|
|
4
4
|
import signal
|
|
5
5
|
import sys
|
|
6
6
|
from collections.abc import Iterable, Sequence
|
|
7
|
-
from enum import Enum, IntEnum
|
|
7
|
+
from enum import Enum, IntEnum, auto
|
|
8
8
|
from functools import wraps
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
from typing import (
|
|
@@ -29,6 +29,36 @@ P = ParamSpec("P") # For capturing function parameters
|
|
|
29
29
|
R = TypeVar("R") # For capturing function return types
|
|
30
30
|
T = TypeVar("T") # For generic iterator types
|
|
31
31
|
|
|
32
|
+
|
|
33
|
+
# StrEnum for Python < 3.11, shared by the ai and agent namespaces.
|
|
34
|
+
if sys.version_info >= (3, 11):
|
|
35
|
+
from enum import StrEnum as StringEnum
|
|
36
|
+
from enum import auto
|
|
37
|
+
# StrEnum in 3.11 already lower-case
|
|
38
|
+
else:
|
|
39
|
+
from enum import Enum, auto
|
|
40
|
+
|
|
41
|
+
# MIT License: https://github.com/irgeek/StrEnum/blob/master/strenum/__init__.py
|
|
42
|
+
class StringEnum(str, Enum):
|
|
43
|
+
# this is a specific version that will lowercase the values
|
|
44
|
+
|
|
45
|
+
def __new__(cls, value: Any, *args: Any, **kwargs: Any) -> "StringEnum":
|
|
46
|
+
if not isinstance(value, (str, auto)):
|
|
47
|
+
raise TypeError( # pragma: no cover
|
|
48
|
+
f"Values of StrEnums must be strings: {value!r} is a {type(value)}"
|
|
49
|
+
)
|
|
50
|
+
return super().__new__(cls, value, *args, **kwargs)
|
|
51
|
+
|
|
52
|
+
def __str__(self) -> str:
|
|
53
|
+
return str(self.value)
|
|
54
|
+
|
|
55
|
+
@staticmethod
|
|
56
|
+
def _generate_next_value_(
|
|
57
|
+
name: str, start: int, count: int, last_values: List[Any]
|
|
58
|
+
) -> str:
|
|
59
|
+
return name.lower()
|
|
60
|
+
|
|
61
|
+
|
|
32
62
|
# Type alias for TagValue return type
|
|
33
63
|
TagValueTuple = Tuple[int, Union[int, float, str]]
|
|
34
64
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import dftracer.python.ai_common as ai_common
|
|
2
|
+
from dftracer.python.dbg.logger import dft_fn as dft_fn_orig
|
|
3
|
+
from dftracer.python.dbg.logger import dftracer as dftracer_orig
|
|
4
|
+
|
|
5
|
+
ai_common.dft_fn = dft_fn_orig # type: ignore[misc]
|
|
6
|
+
ai_common.dftracer = dftracer_orig # type: ignore[misc]
|
|
7
|
+
|
|
8
|
+
from dftracer.python.agent_common import *
|
|
9
|
+
from dftracer.python.agent_init import *
|
{pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/pydftracer.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pydftracer
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.6.post2.dev0
|
|
4
4
|
Summary: Python libs for DFTracer
|
|
5
5
|
Author-email: "Hariharan Devarajan (Hari)" <hariharandev1@llnl.gov>, Ray Andrew Sinurat <raydreww@gmail.com>
|
|
6
6
|
Maintainer-email: "Hariharan Devarajan (Hari)" <hariharandev1@llnl.gov>, Ray Andrew Sinurat <raydreww@gmail.com>
|
{pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/pydftracer.egg-info/SOURCES.txt
RENAMED
|
@@ -19,6 +19,7 @@ docs/source/installation.rst
|
|
|
19
19
|
docs/source/pytorch.rst
|
|
20
20
|
docs/source/quickstart.rst
|
|
21
21
|
docs/source/type_safety.rst
|
|
22
|
+
docs/source/api/agent.rst
|
|
22
23
|
docs/source/api/ai.rst
|
|
23
24
|
docs/source/api/core.rst
|
|
24
25
|
docs/source/api/dynamo.rst
|
|
@@ -26,6 +27,10 @@ docs/source/api/env.rst
|
|
|
26
27
|
docs/source/api/index.rst
|
|
27
28
|
python/dftracer/python/__init__.py
|
|
28
29
|
python/dftracer/python/_version.py
|
|
30
|
+
python/dftracer/python/agent.py
|
|
31
|
+
python/dftracer/python/agent_common.py
|
|
32
|
+
python/dftracer/python/agent_init.py
|
|
33
|
+
python/dftracer/python/agent_langgraph.py
|
|
29
34
|
python/dftracer/python/ai.py
|
|
30
35
|
python/dftracer/python/ai_common.py
|
|
31
36
|
python/dftracer/python/ai_init.py
|
|
@@ -35,6 +40,7 @@ python/dftracer/python/env.py
|
|
|
35
40
|
python/dftracer/python/logger.py
|
|
36
41
|
python/dftracer/python/py.typed
|
|
37
42
|
python/dftracer/python/dbg/__init__.py
|
|
43
|
+
python/dftracer/python/dbg/agent.py
|
|
38
44
|
python/dftracer/python/dbg/ai.py
|
|
39
45
|
python/dftracer/python/dbg/logger.py
|
|
40
46
|
python/dftracer/python/dbg/torch/__init__.py
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"docs/make.bat",
|
|
15
15
|
"docs/requirements.txt",
|
|
16
16
|
"docs/source/ai_ml_guide.rst",
|
|
17
|
+
"docs/source/api/agent.rst",
|
|
17
18
|
"docs/source/api/ai.rst",
|
|
18
19
|
"docs/source/api/core.rst",
|
|
19
20
|
"docs/source/api/dynamo.rst",
|
|
@@ -30,11 +31,16 @@
|
|
|
30
31
|
"docs/source/type_safety.rst",
|
|
31
32
|
"pyproject.toml",
|
|
32
33
|
"python/dftracer/python/__init__.py",
|
|
34
|
+
"python/dftracer/python/agent.py",
|
|
35
|
+
"python/dftracer/python/agent_common.py",
|
|
36
|
+
"python/dftracer/python/agent_init.py",
|
|
37
|
+
"python/dftracer/python/agent_langgraph.py",
|
|
33
38
|
"python/dftracer/python/ai.py",
|
|
34
39
|
"python/dftracer/python/ai_common.py",
|
|
35
40
|
"python/dftracer/python/ai_init.py",
|
|
36
41
|
"python/dftracer/python/common.py",
|
|
37
42
|
"python/dftracer/python/dbg/__init__.py",
|
|
43
|
+
"python/dftracer/python/dbg/agent.py",
|
|
38
44
|
"python/dftracer/python/dbg/ai.py",
|
|
39
45
|
"python/dftracer/python/dbg/logger.py",
|
|
40
46
|
"python/dftracer/python/dbg/torch/__init__.py",
|
|
@@ -51,6 +57,8 @@
|
|
|
51
57
|
"tests/__init__.py",
|
|
52
58
|
"tests/poc/pytorch_profiler/requirements.txt",
|
|
53
59
|
"tests/poc/pytorch_profiler/test.py",
|
|
60
|
+
"tests/test_agent.py",
|
|
61
|
+
"tests/test_agent_langgraph.py",
|
|
54
62
|
"tests/test_ai_logging.py",
|
|
55
63
|
"tests/test_coverage_improvements.py",
|
|
56
64
|
"tests/test_dftracer.py",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/ai_init.py
RENAMED
|
File without changes
|
{pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/dbg/ai.py
RENAMED
|
File without changes
|
{pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/dbg/logger.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/dynamo.py
RENAMED
|
File without changes
|
|
File without changes
|
{pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/logger.py
RENAMED
|
File without changes
|
|
File without changes
|
{pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/torch/__init__.py
RENAMED
|
File without changes
|
{pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/torch/common.py
RENAMED
|
File without changes
|
{pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/dftracer/python/torch/profiler.py
RENAMED
|
File without changes
|
|
File without changes
|
{pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/pydftracer.egg-info/requires.txt
RENAMED
|
File without changes
|
{pydftracer-2.0.5.post2.dev0 → pydftracer-2.0.6.post2.dev0}/python/pydftracer.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|