gptcmd 2.3.4__tar.gz → 2.4.0__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.
- {gptcmd-2.3.4 → gptcmd-2.4.0}/PKG-INFO +3 -3
- {gptcmd-2.3.4 → gptcmd-2.4.0}/README.md +2 -2
- {gptcmd-2.3.4 → gptcmd-2.4.0}/src/gptcmd/__init__.py +1 -1
- {gptcmd-2.3.4 → gptcmd-2.4.0}/src/gptcmd/cli.py +182 -13
- {gptcmd-2.3.4 → gptcmd-2.4.0}/src/gptcmd/llm/openai.py +41 -3
- {gptcmd-2.3.4 → gptcmd-2.4.0}/src/gptcmd.egg-info/PKG-INFO +3 -3
- {gptcmd-2.3.4 → gptcmd-2.4.0}/COPYING.txt +0 -0
- {gptcmd-2.3.4 → gptcmd-2.4.0}/pyproject.toml +0 -0
- {gptcmd-2.3.4 → gptcmd-2.4.0}/setup.cfg +0 -0
- {gptcmd-2.3.4 → gptcmd-2.4.0}/src/gptcmd/config.py +0 -0
- {gptcmd-2.3.4 → gptcmd-2.4.0}/src/gptcmd/config_sample.toml +0 -0
- {gptcmd-2.3.4 → gptcmd-2.4.0}/src/gptcmd/llm/__init__.py +0 -0
- {gptcmd-2.3.4 → gptcmd-2.4.0}/src/gptcmd/macros.py +0 -0
- {gptcmd-2.3.4 → gptcmd-2.4.0}/src/gptcmd/message.py +0 -0
- {gptcmd-2.3.4 → gptcmd-2.4.0}/src/gptcmd.egg-info/SOURCES.txt +0 -0
- {gptcmd-2.3.4 → gptcmd-2.4.0}/src/gptcmd.egg-info/dependency_links.txt +0 -0
- {gptcmd-2.3.4 → gptcmd-2.4.0}/src/gptcmd.egg-info/entry_points.txt +0 -0
- {gptcmd-2.3.4 → gptcmd-2.4.0}/src/gptcmd.egg-info/requires.txt +0 -0
- {gptcmd-2.3.4 → gptcmd-2.4.0}/src/gptcmd.egg-info/top_level.txt +0 -0
- {gptcmd-2.3.4 → gptcmd-2.4.0}/tests/test_llm.py +0 -0
- {gptcmd-2.3.4 → gptcmd-2.4.0}/tests/test_message.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gptcmd
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
4
4
|
Summary: Command line GPT conversation and experimentation environment
|
|
5
5
|
Author-email: Bill Dengler <codeofdusk@gmail.com>
|
|
6
6
|
License-Expression: MPL-2.0
|
|
@@ -221,7 +221,7 @@ The first ten digits of pi are 3.141592653.
|
|
|
221
221
|
With no arguments, the `user`, `assistant`, `system`, and `say` commands open an external text editor (based on your system or Gptcmd configuration) for message composition.
|
|
222
222
|
|
|
223
223
|
### Working with attachments
|
|
224
|
-
OpenAI's latest models, such as `
|
|
224
|
+
OpenAI's latest models, such as `gpt-4o`, support images alongside text content. Images can be attached to messages with the `image` command, which accepts two arguments: the location of the image, either a URL or path to a local file; and the index of the message to which the image should be attached (if unspecified, it defaults to the last). We'll ask GPT to describe an image by creating a user message and attaching an image from Wikimedia Commons:
|
|
225
225
|
|
|
226
226
|
```
|
|
227
227
|
(gpt-4o) user What's in this image?
|
|
@@ -451,7 +451,7 @@ Unset all parameters
|
|
|
451
451
|
```
|
|
452
452
|
|
|
453
453
|
### Names
|
|
454
|
-
GPT allows
|
|
454
|
+
GPT allows messages to be annotated with the name of their author. The `name` command sets the name to be sent with all future messages of the specified role. Its first argument is the role to which this new name should be applied, and its second is the name to use:
|
|
455
455
|
|
|
456
456
|
```
|
|
457
457
|
(gpt-4o) name user Michael
|
|
@@ -201,7 +201,7 @@ The first ten digits of pi are 3.141592653.
|
|
|
201
201
|
With no arguments, the `user`, `assistant`, `system`, and `say` commands open an external text editor (based on your system or Gptcmd configuration) for message composition.
|
|
202
202
|
|
|
203
203
|
### Working with attachments
|
|
204
|
-
OpenAI's latest models, such as `
|
|
204
|
+
OpenAI's latest models, such as `gpt-4o`, support images alongside text content. Images can be attached to messages with the `image` command, which accepts two arguments: the location of the image, either a URL or path to a local file; and the index of the message to which the image should be attached (if unspecified, it defaults to the last). We'll ask GPT to describe an image by creating a user message and attaching an image from Wikimedia Commons:
|
|
205
205
|
|
|
206
206
|
```
|
|
207
207
|
(gpt-4o) user What's in this image?
|
|
@@ -431,7 +431,7 @@ Unset all parameters
|
|
|
431
431
|
```
|
|
432
432
|
|
|
433
433
|
### Names
|
|
434
|
-
GPT allows
|
|
434
|
+
GPT allows messages to be annotated with the name of their author. The `name` command sets the name to be sent with all future messages of the specified role. Its first argument is the role to which this new name should be applied, and its second is the name to use:
|
|
435
435
|
|
|
436
436
|
```
|
|
437
437
|
(gpt-4o) name user Michael
|
|
@@ -18,6 +18,7 @@ import json
|
|
|
18
18
|
import os
|
|
19
19
|
import re
|
|
20
20
|
import shlex
|
|
21
|
+
import signal
|
|
21
22
|
import subprocess
|
|
22
23
|
import sys
|
|
23
24
|
import tempfile
|
|
@@ -816,7 +817,7 @@ class Gptcmd(cmd.Cmd):
|
|
|
816
817
|
"""
|
|
817
818
|
Move the message at the beginning of a range to the end of that range.
|
|
818
819
|
In other words, move <i> <j> moves the ith message of a thread to
|
|
819
|
-
index j.
|
|
820
|
+
index j, using the same inclusive range syntax as other commands.
|
|
820
821
|
"""
|
|
821
822
|
if not arg:
|
|
822
823
|
print("Usage: move <from> <to>")
|
|
@@ -831,17 +832,22 @@ class Gptcmd(cmd.Cmd):
|
|
|
831
832
|
length = len(self._current_thread.messages)
|
|
832
833
|
if i is None:
|
|
833
834
|
i = 0
|
|
835
|
+
elif i < 0:
|
|
836
|
+
i += length
|
|
837
|
+
|
|
834
838
|
if j is None:
|
|
835
839
|
j = length
|
|
836
|
-
|
|
837
|
-
i += length
|
|
838
|
-
if j < 0:
|
|
840
|
+
elif j < 0:
|
|
839
841
|
j += length
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
842
|
+
# Range parsing returns an exclusive end; move needs the included end.
|
|
843
|
+
j -= 1
|
|
844
|
+
|
|
845
|
+
if not (0 <= j < length):
|
|
843
846
|
print("Destination out of bounds")
|
|
844
847
|
return
|
|
848
|
+
if not (0 <= i < length):
|
|
849
|
+
print("Message doesn't exist")
|
|
850
|
+
return
|
|
845
851
|
try:
|
|
846
852
|
msg = self._current_thread.move(i, j)
|
|
847
853
|
except IndexError:
|
|
@@ -1792,7 +1798,7 @@ class Gptcmd(cmd.Cmd):
|
|
|
1792
1798
|
return can_exit # Truthy return values cause the cmdloop to stop
|
|
1793
1799
|
|
|
1794
1800
|
|
|
1795
|
-
def _write_crash_dump(shell: Gptcmd, exc:
|
|
1801
|
+
def _write_crash_dump(shell: Gptcmd, exc: BaseException) -> Optional[str]:
|
|
1796
1802
|
"""
|
|
1797
1803
|
Serialize the current shell into a JSON file and return its absolute
|
|
1798
1804
|
path.
|
|
@@ -1834,6 +1840,169 @@ def _write_crash_dump(shell: Gptcmd, exc: Exception) -> Optional[str]:
|
|
|
1834
1840
|
shell._threads.pop(detached_key, None)
|
|
1835
1841
|
|
|
1836
1842
|
|
|
1843
|
+
def _shell_has_dirty_state(shell: Gptcmd) -> bool:
|
|
1844
|
+
"Return whether the shell has unsaved conversation state."
|
|
1845
|
+
return bool(
|
|
1846
|
+
(shell._detached and shell._detached.dirty)
|
|
1847
|
+
or any(t and t.dirty for t in shell._threads.values())
|
|
1848
|
+
)
|
|
1849
|
+
|
|
1850
|
+
|
|
1851
|
+
def _signal_name(signum: int) -> str:
|
|
1852
|
+
try:
|
|
1853
|
+
return signal.Signals(signum).name
|
|
1854
|
+
except ValueError:
|
|
1855
|
+
return f"signal {signum}"
|
|
1856
|
+
|
|
1857
|
+
|
|
1858
|
+
class _ShutdownDumpHandler:
|
|
1859
|
+
"""
|
|
1860
|
+
Installs best-effort hooks for process shutdown events.
|
|
1861
|
+
"""
|
|
1862
|
+
|
|
1863
|
+
_WINDOWS_HANDLED_EVENTS = {
|
|
1864
|
+
2: "CTRL_CLOSE_EVENT",
|
|
1865
|
+
5: "CTRL_LOGOFF_EVENT",
|
|
1866
|
+
6: "CTRL_SHUTDOWN_EVENT",
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
def __init__(self, shell: Gptcmd):
|
|
1870
|
+
self._shell = shell
|
|
1871
|
+
self._previous_signal_handlers: Dict[int, Any] = {}
|
|
1872
|
+
self._windows_handler = None
|
|
1873
|
+
self._windows_kernel32 = None
|
|
1874
|
+
self._dump_lock = threading.RLock()
|
|
1875
|
+
self._dump_attempted = False
|
|
1876
|
+
|
|
1877
|
+
def install(self) -> None:
|
|
1878
|
+
"Install all shutdown hooks supported by the current platform."
|
|
1879
|
+
self._install_signal_handlers()
|
|
1880
|
+
if os.name == "nt":
|
|
1881
|
+
self._install_windows_console_handler()
|
|
1882
|
+
|
|
1883
|
+
def uninstall(self) -> None:
|
|
1884
|
+
"Remove shutdown hooks installed by this object."
|
|
1885
|
+
for signum, previous_handler in self._previous_signal_handlers.items():
|
|
1886
|
+
try:
|
|
1887
|
+
signal.signal(signum, previous_handler)
|
|
1888
|
+
except (OSError, RuntimeError, ValueError) as e:
|
|
1889
|
+
self._warn(
|
|
1890
|
+
"Could not restore the previous handler for "
|
|
1891
|
+
f"{_signal_name(signum)}: {e}"
|
|
1892
|
+
)
|
|
1893
|
+
self._previous_signal_handlers.clear()
|
|
1894
|
+
if self._windows_handler is None:
|
|
1895
|
+
return
|
|
1896
|
+
try:
|
|
1897
|
+
res = self._windows_kernel32.SetConsoleCtrlHandler(
|
|
1898
|
+
self._windows_handler,
|
|
1899
|
+
False,
|
|
1900
|
+
)
|
|
1901
|
+
except OSError as e:
|
|
1902
|
+
self._warn(
|
|
1903
|
+
f"Could not remove the Windows console shutdown handler: {e}"
|
|
1904
|
+
)
|
|
1905
|
+
return
|
|
1906
|
+
if not res:
|
|
1907
|
+
self._warn("Could not remove the Windows console shutdown handler")
|
|
1908
|
+
self._windows_handler = None
|
|
1909
|
+
self._windows_kernel32 = None
|
|
1910
|
+
|
|
1911
|
+
def _install_signal_handlers(self) -> None:
|
|
1912
|
+
signal_names = ["SIGTERM"]
|
|
1913
|
+
if os.name == "nt":
|
|
1914
|
+
signal_names.append("SIGBREAK")
|
|
1915
|
+
else:
|
|
1916
|
+
signal_names.extend(["SIGHUP", "SIGQUIT"])
|
|
1917
|
+
|
|
1918
|
+
for signal_name in signal_names:
|
|
1919
|
+
signum = getattr(signal, signal_name, None)
|
|
1920
|
+
if signum is None:
|
|
1921
|
+
continue
|
|
1922
|
+
if signum in self._previous_signal_handlers:
|
|
1923
|
+
continue
|
|
1924
|
+
try:
|
|
1925
|
+
previous_handler = signal.getsignal(signum)
|
|
1926
|
+
signal.signal(signum, self._handle_signal)
|
|
1927
|
+
except (OSError, RuntimeError, ValueError) as e:
|
|
1928
|
+
self._warn(
|
|
1929
|
+
"Could not install a shutdown handler for "
|
|
1930
|
+
f"{signal_name}: {e}"
|
|
1931
|
+
)
|
|
1932
|
+
continue
|
|
1933
|
+
self._previous_signal_handlers[signum] = previous_handler
|
|
1934
|
+
|
|
1935
|
+
def _install_windows_console_handler(self) -> None:
|
|
1936
|
+
try:
|
|
1937
|
+
import ctypes
|
|
1938
|
+
from ctypes import wintypes
|
|
1939
|
+
|
|
1940
|
+
handler_type = ctypes.WINFUNCTYPE(wintypes.BOOL, wintypes.DWORD)
|
|
1941
|
+
kernel32 = ctypes.windll.kernel32
|
|
1942
|
+
except (AttributeError, OSError) as e:
|
|
1943
|
+
self._warn(f"Could not load Windows console shutdown support: {e}")
|
|
1944
|
+
return
|
|
1945
|
+
|
|
1946
|
+
def _handler(ctrl_type: int) -> bool:
|
|
1947
|
+
event = self._WINDOWS_HANDLED_EVENTS.get(ctrl_type)
|
|
1948
|
+
if event is None:
|
|
1949
|
+
return False
|
|
1950
|
+
self._dump_once(event)
|
|
1951
|
+
return True
|
|
1952
|
+
|
|
1953
|
+
console_handler = handler_type(_handler)
|
|
1954
|
+
try:
|
|
1955
|
+
res = kernel32.SetConsoleCtrlHandler(console_handler, True)
|
|
1956
|
+
except OSError as e:
|
|
1957
|
+
self._warn(
|
|
1958
|
+
f"Could not install the Windows console shutdown handler: {e}"
|
|
1959
|
+
)
|
|
1960
|
+
return
|
|
1961
|
+
if not res:
|
|
1962
|
+
self._warn(
|
|
1963
|
+
"Could not install the Windows console shutdown handler"
|
|
1964
|
+
)
|
|
1965
|
+
return
|
|
1966
|
+
self._windows_handler = console_handler
|
|
1967
|
+
self._windows_kernel32 = kernel32
|
|
1968
|
+
|
|
1969
|
+
def _handle_signal(self, signum: int, frame: Any) -> None:
|
|
1970
|
+
del frame
|
|
1971
|
+
self._dump_once(_signal_name(signum))
|
|
1972
|
+
raise SystemExit(128 + signum)
|
|
1973
|
+
|
|
1974
|
+
def _dump_once(self, event: str) -> Optional[str]:
|
|
1975
|
+
with self._dump_lock:
|
|
1976
|
+
if self._dump_attempted:
|
|
1977
|
+
return None
|
|
1978
|
+
self._dump_attempted = True
|
|
1979
|
+
|
|
1980
|
+
if not _shell_has_dirty_state(self._shell):
|
|
1981
|
+
return None
|
|
1982
|
+
|
|
1983
|
+
dump_path = _write_crash_dump(
|
|
1984
|
+
self._shell,
|
|
1985
|
+
RuntimeError(f"Process is shutting down: {event}"),
|
|
1986
|
+
)
|
|
1987
|
+
if dump_path:
|
|
1988
|
+
print(
|
|
1989
|
+
f"Crash dump written to {dump_path}",
|
|
1990
|
+
file=sys.stderr,
|
|
1991
|
+
flush=True,
|
|
1992
|
+
)
|
|
1993
|
+
return dump_path
|
|
1994
|
+
|
|
1995
|
+
@staticmethod
|
|
1996
|
+
def _warn(message: str) -> None:
|
|
1997
|
+
warnings.warn(
|
|
1998
|
+
message
|
|
1999
|
+
+ "\nGptcmd may be unable to save a crash dump in the event of "
|
|
2000
|
+
+ "unexpected shutdown!",
|
|
2001
|
+
RuntimeWarning,
|
|
2002
|
+
stacklevel=3,
|
|
2003
|
+
)
|
|
2004
|
+
|
|
2005
|
+
|
|
1837
2006
|
class ExperimentalAPIWarning(Warning):
|
|
1838
2007
|
pass
|
|
1839
2008
|
|
|
@@ -1897,17 +2066,15 @@ def _run(shell_cls) -> bool:
|
|
|
1897
2066
|
shell.do_account(args.account, _print_on_success=False)
|
|
1898
2067
|
if args.model:
|
|
1899
2068
|
shell.do_model(args.model, _print_on_success=False)
|
|
2069
|
+
shutdown_dump_handler = _ShutdownDumpHandler(shell)
|
|
2070
|
+
shutdown_dump_handler.install()
|
|
1900
2071
|
try:
|
|
1901
2072
|
shell.cmdloop()
|
|
1902
2073
|
except SystemExit:
|
|
1903
2074
|
# Don't write a crash dump
|
|
1904
2075
|
raise
|
|
1905
2076
|
except BaseException as e:
|
|
1906
|
-
|
|
1907
|
-
should_save = (shell._detached and shell._detached.dirty) or any(
|
|
1908
|
-
t and t.dirty for t in shell._threads.values()
|
|
1909
|
-
)
|
|
1910
|
-
if should_save:
|
|
2077
|
+
if _shell_has_dirty_state(shell):
|
|
1911
2078
|
dump_path = _write_crash_dump(shell, e)
|
|
1912
2079
|
if dump_path:
|
|
1913
2080
|
# Hack: Print the "crash dump" notice after the traceback
|
|
@@ -1919,6 +2086,8 @@ def _run(shell_cls) -> bool:
|
|
|
1919
2086
|
)
|
|
1920
2087
|
)
|
|
1921
2088
|
raise
|
|
2089
|
+
finally:
|
|
2090
|
+
shutdown_dump_handler.uninstall()
|
|
1922
2091
|
return True
|
|
1923
2092
|
|
|
1924
2093
|
|
|
@@ -26,10 +26,35 @@ from ..message import Audio, Image, Message, MessageRole
|
|
|
26
26
|
import openai
|
|
27
27
|
|
|
28
28
|
ModelCostInfo = namedtuple(
|
|
29
|
-
"ModelCostInfo",
|
|
29
|
+
"ModelCostInfo",
|
|
30
|
+
(
|
|
31
|
+
"prompt_scale",
|
|
32
|
+
"sampled_scale",
|
|
33
|
+
"cache_discount_factor",
|
|
34
|
+
"long_prompt_threshold",
|
|
35
|
+
"long_prompt_factor",
|
|
36
|
+
"long_sampled_factor",
|
|
37
|
+
),
|
|
38
|
+
defaults=(None, Decimal("1"), Decimal("1")),
|
|
30
39
|
)
|
|
31
40
|
|
|
32
41
|
OPENAI_COSTS: Dict[str, ModelCostInfo] = {
|
|
42
|
+
"gpt-5.5-2026-04-23": ModelCostInfo(
|
|
43
|
+
Decimal("5") / Decimal("1000000"),
|
|
44
|
+
Decimal("30") / Decimal("1000000"),
|
|
45
|
+
Decimal("0.1"),
|
|
46
|
+
272000,
|
|
47
|
+
Decimal("2"),
|
|
48
|
+
Decimal("1.5"),
|
|
49
|
+
),
|
|
50
|
+
"gpt-5.4-2026-03-05": ModelCostInfo(
|
|
51
|
+
Decimal("2.5") / Decimal("1000000"),
|
|
52
|
+
Decimal("15") / Decimal("1000000"),
|
|
53
|
+
Decimal("0.1"),
|
|
54
|
+
272000,
|
|
55
|
+
Decimal("2"),
|
|
56
|
+
Decimal("1.5"),
|
|
57
|
+
),
|
|
33
58
|
"gpt-5.2-2025-12-11": ModelCostInfo(
|
|
34
59
|
Decimal("1.75") / Decimal("1000000"),
|
|
35
60
|
Decimal("14") / Decimal("1000000"),
|
|
@@ -280,10 +305,21 @@ class OpenAI(LLMProvider):
|
|
|
280
305
|
cached_prompt_tokens = min(max(cached_prompt_tokens, 0), prompt_tokens)
|
|
281
306
|
uncached_prompt_tokens = prompt_tokens - cached_prompt_tokens
|
|
282
307
|
sampled_tokens = max(0, sampled_tokens)
|
|
308
|
+
long_context = (
|
|
309
|
+
info.long_prompt_threshold is not None
|
|
310
|
+
and prompt_tokens > info.long_prompt_threshold
|
|
311
|
+
)
|
|
312
|
+
prompt_factor = (
|
|
313
|
+
info.long_prompt_factor if long_context else Decimal("1")
|
|
314
|
+
)
|
|
315
|
+
sampled_factor = (
|
|
316
|
+
info.long_sampled_factor if long_context else Decimal("1")
|
|
317
|
+
)
|
|
318
|
+
cached_prompt_scale *= prompt_factor
|
|
283
319
|
return (
|
|
284
|
-
Decimal(uncached_prompt_tokens) * info.prompt_scale
|
|
320
|
+
Decimal(uncached_prompt_tokens) * info.prompt_scale * prompt_factor
|
|
285
321
|
+ Decimal(cached_prompt_tokens) * cached_prompt_scale
|
|
286
|
-
+ Decimal(sampled_tokens) * info.sampled_scale
|
|
322
|
+
+ Decimal(sampled_tokens) * info.sampled_scale * sampled_factor
|
|
287
323
|
) * Decimal("100")
|
|
288
324
|
|
|
289
325
|
def complete(self, messages: Sequence[Message]) -> LLMResponse:
|
|
@@ -371,6 +407,8 @@ class OpenAI(LLMProvider):
|
|
|
371
407
|
|
|
372
408
|
def get_best_model(self):
|
|
373
409
|
BEST_MODELS = (
|
|
410
|
+
"gpt-5.5",
|
|
411
|
+
"gpt-5.4",
|
|
374
412
|
"gpt-5.2",
|
|
375
413
|
"gpt-5.1",
|
|
376
414
|
"gpt-5",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gptcmd
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
4
4
|
Summary: Command line GPT conversation and experimentation environment
|
|
5
5
|
Author-email: Bill Dengler <codeofdusk@gmail.com>
|
|
6
6
|
License-Expression: MPL-2.0
|
|
@@ -221,7 +221,7 @@ The first ten digits of pi are 3.141592653.
|
|
|
221
221
|
With no arguments, the `user`, `assistant`, `system`, and `say` commands open an external text editor (based on your system or Gptcmd configuration) for message composition.
|
|
222
222
|
|
|
223
223
|
### Working with attachments
|
|
224
|
-
OpenAI's latest models, such as `
|
|
224
|
+
OpenAI's latest models, such as `gpt-4o`, support images alongside text content. Images can be attached to messages with the `image` command, which accepts two arguments: the location of the image, either a URL or path to a local file; and the index of the message to which the image should be attached (if unspecified, it defaults to the last). We'll ask GPT to describe an image by creating a user message and attaching an image from Wikimedia Commons:
|
|
225
225
|
|
|
226
226
|
```
|
|
227
227
|
(gpt-4o) user What's in this image?
|
|
@@ -451,7 +451,7 @@ Unset all parameters
|
|
|
451
451
|
```
|
|
452
452
|
|
|
453
453
|
### Names
|
|
454
|
-
GPT allows
|
|
454
|
+
GPT allows messages to be annotated with the name of their author. The `name` command sets the name to be sent with all future messages of the specified role. Its first argument is the role to which this new name should be applied, and its second is the name to use:
|
|
455
455
|
|
|
456
456
|
```
|
|
457
457
|
(gpt-4o) name user Michael
|
|
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
|