zrb 1.5.13__py3-none-any.whl → 1.5.15__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.
- zrb/llm_config.py +11 -4
- zrb/task/llm/agent.py +23 -7
- zrb/task/llm/config.py +9 -3
- zrb/task/llm/context_enrichment.py +10 -5
- zrb/task/llm/error.py +6 -2
- zrb/task/llm/history_summarization.py +10 -4
- zrb/task/llm/print_node.py +11 -11
- zrb/task/llm/tool_wrapper.py +10 -2
- zrb/task/llm_task.py +21 -10
- {zrb-1.5.13.dist-info → zrb-1.5.15.dist-info}/METADATA +1 -1
- {zrb-1.5.13.dist-info → zrb-1.5.15.dist-info}/RECORD +13 -13
- {zrb-1.5.13.dist-info → zrb-1.5.15.dist-info}/WHEEL +0 -0
- {zrb-1.5.13.dist-info → zrb-1.5.15.dist-info}/entry_points.txt +0 -0
zrb/llm_config.py
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
import os
|
2
|
+
from typing import TYPE_CHECKING, Any
|
2
3
|
|
3
|
-
|
4
|
-
from pydantic_ai.models
|
5
|
-
from pydantic_ai.providers import Provider
|
6
|
-
|
4
|
+
if TYPE_CHECKING:
|
5
|
+
from pydantic_ai.models import Model
|
6
|
+
from pydantic_ai.providers import Provider
|
7
|
+
else:
|
8
|
+
Model = Any
|
9
|
+
Provider = Any
|
7
10
|
|
8
11
|
from zrb.util.string.conversion import to_boolean
|
9
12
|
|
@@ -135,6 +138,8 @@ class LLMConfig:
|
|
135
138
|
return self._default_provider
|
136
139
|
if self._default_model_base_url is None and self._default_model_api_key is None:
|
137
140
|
return "openai"
|
141
|
+
from pydantic_ai.providers.openai import OpenAIProvider
|
142
|
+
|
138
143
|
return OpenAIProvider(
|
139
144
|
base_url=self._default_model_base_url, api_key=self._default_model_api_key
|
140
145
|
)
|
@@ -178,6 +183,8 @@ class LLMConfig:
|
|
178
183
|
model_name = self._get_model_name()
|
179
184
|
if model_name is None:
|
180
185
|
return None
|
186
|
+
from pydantic_ai.models.openai import OpenAIModel
|
187
|
+
|
181
188
|
return OpenAIModel(
|
182
189
|
model_name=model_name,
|
183
190
|
provider=self.get_default_model_provider(),
|
zrb/task/llm/agent.py
CHANGED
@@ -1,12 +1,22 @@
|
|
1
1
|
from collections.abc import Callable
|
2
|
+
from typing import TYPE_CHECKING, Any
|
2
3
|
|
3
|
-
|
4
|
-
from
|
5
|
-
from pydantic_ai
|
6
|
-
from pydantic_ai.
|
7
|
-
from pydantic_ai.
|
8
|
-
from pydantic_ai.models import Model
|
9
|
-
from pydantic_ai.settings import ModelSettings
|
4
|
+
if TYPE_CHECKING:
|
5
|
+
from openai import APIError
|
6
|
+
from pydantic_ai import Agent, Tool
|
7
|
+
from pydantic_ai.agent import AgentRun
|
8
|
+
from pydantic_ai.mcp import MCPServer
|
9
|
+
from pydantic_ai.models import Model
|
10
|
+
from pydantic_ai.settings import ModelSettings
|
11
|
+
else:
|
12
|
+
APIError = Any
|
13
|
+
Agent = Any
|
14
|
+
Tool = Any
|
15
|
+
AgentRun = Any
|
16
|
+
MCPServer = Any
|
17
|
+
ModelMessagesTypeAdapter = Any
|
18
|
+
Model = Any
|
19
|
+
ModelSettings = Any
|
10
20
|
|
11
21
|
from zrb.context.any_context import AnyContext
|
12
22
|
from zrb.context.any_shared_context import AnySharedContext
|
@@ -32,6 +42,8 @@ def create_agent_instance(
|
|
32
42
|
) -> Agent:
|
33
43
|
"""Creates a new Agent instance with configured tools and servers."""
|
34
44
|
# Get tools
|
45
|
+
from pydantic_ai import Agent, Tool
|
46
|
+
|
35
47
|
tools_or_callables = list(tools_attr(ctx) if callable(tools_attr) else tools_attr)
|
36
48
|
tools_or_callables.extend(additional_tools)
|
37
49
|
tools = []
|
@@ -71,6 +83,8 @@ def get_agent(
|
|
71
83
|
additional_mcp_servers: list[MCPServer],
|
72
84
|
) -> Agent:
|
73
85
|
"""Retrieves the configured Agent instance or creates one if necessary."""
|
86
|
+
from pydantic_ai import Agent
|
87
|
+
|
74
88
|
if isinstance(agent_attr, Agent):
|
75
89
|
return agent_attr
|
76
90
|
if callable(agent_attr):
|
@@ -116,6 +130,8 @@ async def run_agent_iteration(
|
|
116
130
|
Raises:
|
117
131
|
Exception: If any error occurs during agent execution.
|
118
132
|
"""
|
133
|
+
from pydantic_ai.messages import ModelMessagesTypeAdapter
|
134
|
+
|
119
135
|
async with agent.run_mcp_servers():
|
120
136
|
async with agent.iter(
|
121
137
|
user_prompt=user_prompt,
|
zrb/task/llm/config.py
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
-
from typing import Callable
|
1
|
+
from typing import TYPE_CHECKING, Any, Callable
|
2
2
|
|
3
|
-
|
4
|
-
from pydantic_ai.
|
3
|
+
if TYPE_CHECKING:
|
4
|
+
from pydantic_ai.models import Model
|
5
|
+
from pydantic_ai.settings import ModelSettings
|
6
|
+
else:
|
7
|
+
Model = Any
|
8
|
+
ModelSettings = Any
|
5
9
|
|
6
10
|
from zrb.attr.type import StrAttr, fstring
|
7
11
|
from zrb.context.any_context import AnyContext
|
@@ -59,6 +63,8 @@ def get_model(
|
|
59
63
|
render_model_api_key: bool,
|
60
64
|
) -> str | Model | None:
|
61
65
|
"""Gets the model instance or name, handling defaults and configuration."""
|
66
|
+
from pydantic_ai.models import Model
|
67
|
+
|
62
68
|
model = get_attr(ctx, model_attr, None, auto_render=render_model)
|
63
69
|
if model is None:
|
64
70
|
return default_llm_config.get_default_model()
|
@@ -1,12 +1,9 @@
|
|
1
1
|
import json
|
2
2
|
import traceback
|
3
3
|
from textwrap import dedent
|
4
|
-
from typing import Any
|
4
|
+
from typing import TYPE_CHECKING, Any
|
5
5
|
|
6
6
|
from pydantic import BaseModel
|
7
|
-
from pydantic_ai import Agent
|
8
|
-
from pydantic_ai.models import Model
|
9
|
-
from pydantic_ai.settings import ModelSettings
|
10
7
|
|
11
8
|
from zrb.attr.type import BoolAttr, IntAttr
|
12
9
|
from zrb.context.any_context import AnyContext
|
@@ -15,6 +12,13 @@ from zrb.task.llm.agent import run_agent_iteration
|
|
15
12
|
from zrb.task.llm.typing import ListOfDict
|
16
13
|
from zrb.util.attr import get_bool_attr, get_int_attr
|
17
14
|
|
15
|
+
if TYPE_CHECKING:
|
16
|
+
from pydantic_ai.models import Model
|
17
|
+
from pydantic_ai.settings import ModelSettings
|
18
|
+
else:
|
19
|
+
Model = Any
|
20
|
+
ModelSettings = Any
|
21
|
+
|
18
22
|
|
19
23
|
class EnrichmentConfig(BaseModel):
|
20
24
|
model_config = {"arbitrary_types_allowed": True}
|
@@ -35,6 +39,8 @@ async def enrich_context(
|
|
35
39
|
history_list: ListOfDict,
|
36
40
|
) -> dict[str, Any]:
|
37
41
|
"""Runs an LLM call to extract key info and merge it into the context."""
|
42
|
+
from pydantic_ai import Agent
|
43
|
+
|
38
44
|
ctx.log_info("Attempting to enrich conversation context...")
|
39
45
|
# Prepare context and history for the enrichment prompt
|
40
46
|
try:
|
@@ -160,7 +166,6 @@ async def maybe_enrich_context(
|
|
160
166
|
context_enrichment_threshold_attr,
|
161
167
|
render_context_enrichment_threshold,
|
162
168
|
):
|
163
|
-
# Use the enrich_context function now defined in this file
|
164
169
|
return await enrich_context(
|
165
170
|
ctx=ctx,
|
166
171
|
config=EnrichmentConfig(
|
zrb/task/llm/error.py
CHANGED
@@ -1,9 +1,13 @@
|
|
1
1
|
import json
|
2
|
-
from typing import Optional
|
2
|
+
from typing import TYPE_CHECKING, Any, Optional
|
3
3
|
|
4
|
-
from openai import APIError
|
5
4
|
from pydantic import BaseModel
|
6
5
|
|
6
|
+
if TYPE_CHECKING:
|
7
|
+
from openai import APIError
|
8
|
+
else:
|
9
|
+
APIError = Any
|
10
|
+
|
7
11
|
|
8
12
|
# Define a structured error model for tool execution failures
|
9
13
|
class ToolExecutionError(BaseModel):
|
@@ -1,10 +1,7 @@
|
|
1
1
|
import json
|
2
|
-
from typing import Any
|
2
|
+
from typing import TYPE_CHECKING, Any
|
3
3
|
|
4
4
|
from pydantic import BaseModel
|
5
|
-
from pydantic_ai import Agent
|
6
|
-
from pydantic_ai.models import Model
|
7
|
-
from pydantic_ai.settings import ModelSettings
|
8
5
|
|
9
6
|
from zrb.attr.type import BoolAttr, IntAttr
|
10
7
|
from zrb.context.any_context import AnyContext
|
@@ -13,6 +10,13 @@ from zrb.task.llm.agent import run_agent_iteration
|
|
13
10
|
from zrb.task.llm.typing import ListOfDict
|
14
11
|
from zrb.util.attr import get_bool_attr, get_int_attr
|
15
12
|
|
13
|
+
if TYPE_CHECKING:
|
14
|
+
from pydantic_ai.models import Model
|
15
|
+
from pydantic_ai.settings import ModelSettings
|
16
|
+
else:
|
17
|
+
Model = Any
|
18
|
+
ModelSettings = Any
|
19
|
+
|
16
20
|
|
17
21
|
def get_history_part_len(history_list: ListOfDict) -> int:
|
18
22
|
"""Calculates the total number of 'parts' in a history list."""
|
@@ -90,6 +94,8 @@ async def summarize_history(
|
|
90
94
|
history_list: ListOfDict,
|
91
95
|
) -> dict[str, Any]:
|
92
96
|
"""Runs an LLM call to summarize history and update the context."""
|
97
|
+
from pydantic_ai import Agent
|
98
|
+
|
93
99
|
ctx.log_info("Attempting to summarize conversation history...")
|
94
100
|
|
95
101
|
summarization_agent = Agent(
|
zrb/task/llm/print_node.py
CHANGED
@@ -1,22 +1,22 @@
|
|
1
1
|
from collections.abc import Callable
|
2
2
|
from typing import Any
|
3
3
|
|
4
|
-
from pydantic_ai import Agent
|
5
|
-
from pydantic_ai.messages import (
|
6
|
-
FinalResultEvent,
|
7
|
-
FunctionToolCallEvent,
|
8
|
-
FunctionToolResultEvent,
|
9
|
-
PartDeltaEvent,
|
10
|
-
PartStartEvent,
|
11
|
-
TextPartDelta,
|
12
|
-
ToolCallPartDelta,
|
13
|
-
)
|
14
|
-
|
15
4
|
from zrb.util.cli.style import stylize_faint
|
16
5
|
|
17
6
|
|
18
7
|
async def print_node(print_func: Callable, agent_run: Any, node: Any):
|
19
8
|
"""Prints the details of an agent execution node using a provided print function."""
|
9
|
+
from pydantic_ai import Agent
|
10
|
+
from pydantic_ai.messages import (
|
11
|
+
FinalResultEvent,
|
12
|
+
FunctionToolCallEvent,
|
13
|
+
FunctionToolResultEvent,
|
14
|
+
PartDeltaEvent,
|
15
|
+
PartStartEvent,
|
16
|
+
TextPartDelta,
|
17
|
+
ToolCallPartDelta,
|
18
|
+
)
|
19
|
+
|
20
20
|
if Agent.is_user_prompt_node(node):
|
21
21
|
# A user prompt node => The user has provided input
|
22
22
|
print_func(stylize_faint(f">> UserPromptNode: {node.user_prompt}"))
|
zrb/task/llm/tool_wrapper.py
CHANGED
@@ -3,16 +3,22 @@ import inspect
|
|
3
3
|
import traceback
|
4
4
|
import typing
|
5
5
|
from collections.abc import Callable
|
6
|
-
|
7
|
-
from pydantic_ai import RunContext, Tool
|
6
|
+
from typing import TYPE_CHECKING, Any
|
8
7
|
|
9
8
|
from zrb.context.any_context import AnyContext
|
10
9
|
from zrb.task.llm.error import ToolExecutionError
|
11
10
|
from zrb.util.run import run_async
|
12
11
|
|
12
|
+
if TYPE_CHECKING:
|
13
|
+
from pydantic_ai import Tool
|
14
|
+
else:
|
15
|
+
Tool = Any
|
16
|
+
|
13
17
|
|
14
18
|
def wrap_tool(func: Callable, ctx: AnyContext) -> Tool:
|
15
19
|
"""Wraps a tool function to handle exceptions and context propagation."""
|
20
|
+
from pydantic_ai import RunContext, Tool
|
21
|
+
|
16
22
|
original_sig = inspect.signature(func)
|
17
23
|
# Use helper function for clarity
|
18
24
|
needs_run_context_for_pydantic = _has_context_parameter(original_sig, RunContext)
|
@@ -123,6 +129,8 @@ def _adjust_signature(
|
|
123
129
|
# (we inject it). So, the wrapper's signature should be the original signature,
|
124
130
|
# minus any parameters annotated with RunContext or AnyContext.
|
125
131
|
|
132
|
+
from pydantic_ai import RunContext
|
133
|
+
|
126
134
|
params_for_schema = [
|
127
135
|
param
|
128
136
|
for param in original_sig.parameters.values()
|
zrb/task/llm_task.py
CHANGED
@@ -1,11 +1,18 @@
|
|
1
1
|
import json
|
2
2
|
from collections.abc import Callable
|
3
|
-
from typing import Any
|
3
|
+
from typing import TYPE_CHECKING, Any
|
4
4
|
|
5
|
-
|
6
|
-
from pydantic_ai
|
7
|
-
from pydantic_ai.
|
8
|
-
from pydantic_ai.
|
5
|
+
if TYPE_CHECKING:
|
6
|
+
from pydantic_ai import Agent, Tool
|
7
|
+
from pydantic_ai.mcp import MCPServer
|
8
|
+
from pydantic_ai.models import Model
|
9
|
+
from pydantic_ai.settings import ModelSettings
|
10
|
+
else:
|
11
|
+
Agent = Any
|
12
|
+
Tool = Any
|
13
|
+
MCPServer = Any
|
14
|
+
Model = Any
|
15
|
+
ModelSettings = Any
|
9
16
|
|
10
17
|
from zrb.attr.type import BoolAttr, IntAttr, StrAttr, fstring
|
11
18
|
from zrb.context.any_context import AnyContext
|
@@ -39,7 +46,10 @@ from zrb.task.llm.prompt import (
|
|
39
46
|
from zrb.util.cli.style import stylize_faint
|
40
47
|
from zrb.xcom.xcom import Xcom
|
41
48
|
|
42
|
-
|
49
|
+
if TYPE_CHECKING:
|
50
|
+
ToolOrCallable = Tool | Callable
|
51
|
+
else:
|
52
|
+
ToolOrCallable = Any
|
43
53
|
|
44
54
|
|
45
55
|
class LLMTask(BaseTask):
|
@@ -80,10 +90,11 @@ class LLMTask(BaseTask):
|
|
80
90
|
context_enrichment_threshold: IntAttr | None = None,
|
81
91
|
render_context_enrichment_threshold: bool = True,
|
82
92
|
tools: (
|
83
|
-
list[ToolOrCallable]
|
93
|
+
list["ToolOrCallable"]
|
94
|
+
| Callable[[AnySharedContext], list["ToolOrCallable"]]
|
84
95
|
) = [],
|
85
96
|
mcp_servers: (
|
86
|
-
list[MCPServer] | Callable[[AnySharedContext], list[MCPServer]]
|
97
|
+
list["MCPServer"] | Callable[[AnySharedContext], list["MCPServer"]]
|
87
98
|
) = [],
|
88
99
|
conversation_history: (
|
89
100
|
ConversationHistoryData
|
@@ -166,9 +177,9 @@ class LLMTask(BaseTask):
|
|
166
177
|
self._context_enrichment_threshold = context_enrichment_threshold
|
167
178
|
self._render_context_enrichment_threshold = render_context_enrichment_threshold
|
168
179
|
self._tools = tools
|
169
|
-
self._additional_tools: list[ToolOrCallable] = []
|
180
|
+
self._additional_tools: list["ToolOrCallable"] = []
|
170
181
|
self._mcp_servers = mcp_servers
|
171
|
-
self._additional_mcp_servers: list[MCPServer] = []
|
182
|
+
self._additional_mcp_servers: list["MCPServer"] = []
|
172
183
|
self._conversation_history = conversation_history
|
173
184
|
self._conversation_history_reader = conversation_history_reader
|
174
185
|
self._conversation_history_writer = conversation_history_writer
|
@@ -241,7 +241,7 @@ zrb/input/option_input.py,sha256=TQB82ko5odgzkULEizBZi0e9TIHEbIgvdP0AR3RhA74,213
|
|
241
241
|
zrb/input/password_input.py,sha256=szBojWxSP9QJecgsgA87OIYwQrY2AQ3USIKdDZY6snU,1465
|
242
242
|
zrb/input/str_input.py,sha256=NevZHX9rf1g8eMatPyy-kUX3DglrVAQpzvVpKAzf7bA,81
|
243
243
|
zrb/input/text_input.py,sha256=shvVbc2U8Is36h23M5lcW8IEwKc9FR-4uEPZZroj3rU,3377
|
244
|
-
zrb/llm_config.py,sha256=
|
244
|
+
zrb/llm_config.py,sha256=alAdk23Hnd4JnEQsLcquBjz4PWn-QGaVG5NCrzF5XrI,9702
|
245
245
|
zrb/runner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
246
246
|
zrb/runner/cli.py,sha256=0mT0oO_yEhc8N4nYCJNujhgLjVykZ0B-kAOFXyAvAqM,6672
|
247
247
|
zrb/runner/common_util.py,sha256=0zhZn1Jdmr194_nsL5_L-Kn9-_NDpMTI2z6_LXUQJ-U,1369
|
@@ -311,18 +311,18 @@ zrb/task/base_trigger.py,sha256=jC722rDvodaBLeNaFghkTyv1u0QXrK6BLZUUqcmBJ7Q,4581
|
|
311
311
|
zrb/task/cmd_task.py,sha256=xFAdOvLDK9Qaye40T_lG3K6AIKgbPAMHk_3GIAYeJAM,10750
|
312
312
|
zrb/task/http_check.py,sha256=Gf5rOB2Se2EdizuN9rp65HpGmfZkGc-clIAlHmPVehs,2565
|
313
313
|
zrb/task/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
314
|
-
zrb/task/llm/agent.py,sha256=
|
315
|
-
zrb/task/llm/config.py,sha256=
|
314
|
+
zrb/task/llm/agent.py,sha256=pZAbn0vQOXFkJqnHBo8rfFq3OZD3yePr39jzcRqn43A,5248
|
315
|
+
zrb/task/llm/config.py,sha256=R6mkbm4d5ecN4KjjZaXbqNq9-8bXfdUGl_BML8hUWqY,3205
|
316
316
|
zrb/task/llm/context.py,sha256=s313jXooOp8ht7j2sc3-d8xyW7oWs9bFv4KEyjicwys,3893
|
317
|
-
zrb/task/llm/context_enrichment.py,sha256=
|
318
|
-
zrb/task/llm/error.py,sha256=
|
317
|
+
zrb/task/llm/context_enrichment.py,sha256=lLPCtSSdB0jyReB3rk5taNvFPpXMmjDZ_Ro_Fz5GX68,5963
|
318
|
+
zrb/task/llm/error.py,sha256=27DQXSG8SH1-XuvXFdZQKzP39wZDWmd_YnSTz6DJKKI,3690
|
319
319
|
zrb/task/llm/history.py,sha256=LnrJdXLyo2qz-bNCwLorhoqGmgSiPTUU0bzY63w67-E,9257
|
320
|
-
zrb/task/llm/history_summarization.py,sha256=
|
321
|
-
zrb/task/llm/print_node.py,sha256=
|
320
|
+
zrb/task/llm/history_summarization.py,sha256=0cWChp4OE_OiaNDhHRWi4rwHKTHsqWLYy3pS5IAIHpQ,6293
|
321
|
+
zrb/task/llm/print_node.py,sha256=dxwSOZ_DAFdrVSRIAEaxUjgbXWRtju1H87AtC9AJRIM,4470
|
322
322
|
zrb/task/llm/prompt.py,sha256=0uN96mPiq5o28Bz_f7wWmOD6-DJYD-nc_N5RovYz3Js,4719
|
323
|
-
zrb/task/llm/tool_wrapper.py,sha256=
|
323
|
+
zrb/task/llm/tool_wrapper.py,sha256=Xygd4VCY3ykjVv63pqlTI16ZG41ySkp683_5VTnL-Zo,6481
|
324
324
|
zrb/task/llm/typing.py,sha256=c8VAuPBw_4A3DxfYdydkgedaP-LU61W9_wj3m3CAX1E,58
|
325
|
-
zrb/task/llm_task.py,sha256=
|
325
|
+
zrb/task/llm_task.py,sha256=ABIhleg8n1d33FMJq2OqSigeXf8ROnEfUV4_9KmLoNQ,15220
|
326
326
|
zrb/task/make_task.py,sha256=PD3b_aYazthS8LHeJsLAhwKDEgdurQZpymJDKeN60u0,2265
|
327
327
|
zrb/task/rsync_task.py,sha256=GSL9144bmp6F0EckT6m-2a1xG25AzrrWYzH4k3SVUKM,6370
|
328
328
|
zrb/task/scaffolder.py,sha256=rME18w1HJUHXgi9eTYXx_T2G4JdqDYzBoNOkdOOo5-o,6806
|
@@ -363,7 +363,7 @@ zrb/util/string/name.py,sha256=SXEfxJ1-tDOzHqmSV8kvepRVyMqs2XdV_vyoh_9XUu0,1584
|
|
363
363
|
zrb/util/todo.py,sha256=VGISej2KQZERpornK-8X7bysp4JydMrMUTnG8B0-liI,20708
|
364
364
|
zrb/xcom/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
365
365
|
zrb/xcom/xcom.py,sha256=o79rxR9wphnShrcIushA0Qt71d_p3ZTxjNf7x9hJB78,1571
|
366
|
-
zrb-1.5.
|
367
|
-
zrb-1.5.
|
368
|
-
zrb-1.5.
|
369
|
-
zrb-1.5.
|
366
|
+
zrb-1.5.15.dist-info/METADATA,sha256=G1B30COaisd9TjKv4-r0FpOwQnU-N5UBk5UEexfN2cQ,8347
|
367
|
+
zrb-1.5.15.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
368
|
+
zrb-1.5.15.dist-info/entry_points.txt,sha256=-Pg3ElWPfnaSM-XvXqCxEAa-wfVI6BEgcs386s8C8v8,46
|
369
|
+
zrb-1.5.15.dist-info/RECORD,,
|
File without changes
|
File without changes
|