mirror of
https://github.com/langchain-ai/deepagents.git
synced 2026-07-21 17:25:26 -04:00
fix(code): report same-version dependency updates (#4146)
The installer now distinguishes a true no-op reinstall from a same-version reinstall that still moves transitive packages. When `uv` reports dependency changes, the final status and footer say dependencies were updated, and the raw install output is saved so users can inspect the full details after abbreviated terminal output.
This commit is contained in:
@@ -241,6 +241,71 @@ can_prompt() {
|
||||
{ : < /dev/tty; } 2>/dev/null
|
||||
}
|
||||
|
||||
path_is_under_home() {
|
||||
local path="$1"
|
||||
local home_real=""
|
||||
local path_real=""
|
||||
[ -n "${HOME:-}" ] || return 1
|
||||
[ -d "$path" ] || return 1
|
||||
home_real=$(cd "$HOME" 2>/dev/null && pwd -P) || return 1
|
||||
path_real=$(cd "$path" 2>/dev/null && pwd -P) || return 1
|
||||
case "$path_real" in
|
||||
"$home_real"/*) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
prepare_install_log_dir() {
|
||||
local cache_root="$1"
|
||||
local dir="${cache_root}/deepagents-code"
|
||||
[ -n "$cache_root" ] || return 1
|
||||
[ ! -L "$cache_root" ] || return 1
|
||||
[ ! -L "$dir" ] || return 1
|
||||
if [ ! -d "$cache_root" ]; then
|
||||
mkdir -m 700 -p "$cache_root" 2>/dev/null || return 1
|
||||
fi
|
||||
[ -d "$cache_root" ] && [ ! -L "$cache_root" ] || return 1
|
||||
if [ -e "$dir" ]; then
|
||||
[ -d "$dir" ] && [ ! -L "$dir" ] || return 1
|
||||
else
|
||||
mkdir -m 700 "$dir" 2>/dev/null || return 1
|
||||
fi
|
||||
if [ "$(id -u)" -eq 0 ]; then
|
||||
path_is_under_home "$dir" || return 1
|
||||
fi
|
||||
printf '%s\n' "$dir"
|
||||
}
|
||||
|
||||
fix_install_log_owner() {
|
||||
[ -n "${INSTALL_LOG:-}" ] || return 0
|
||||
[ "$(id -u)" -eq 0 ] || return 0
|
||||
[ -n "${TARGET_USER:-}" ] && [ "$TARGET_USER" != "root" ] || return 0
|
||||
[ -d "$install_log_dir" ] && [ ! -L "$install_log_dir" ] || return 0
|
||||
path_is_under_home "$install_log_dir" || return 0
|
||||
if ! chown -h "$TARGET_USER" "$install_log_dir" 2>&1; then
|
||||
log_warn "Could not fix ownership of $install_log_dir for user ${TARGET_USER}."
|
||||
fi
|
||||
if [ -f "$INSTALL_LOG" ] && [ ! -L "$INSTALL_LOG" ]; then
|
||||
if ! chown -h "$TARGET_USER" "$INSTALL_LOG" 2>&1; then
|
||||
log_warn "Could not fix ownership of $INSTALL_LOG for user ${TARGET_USER}."
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
copy_install_log() {
|
||||
[ -n "${INSTALL_LOG:-}" ] || return 1
|
||||
[ -n "${install_log_dir:-}" ] || return 1
|
||||
[ -d "$install_log_dir" ] && [ ! -L "$install_log_dir" ] || return 1
|
||||
if [ "$(id -u)" -eq 0 ]; then
|
||||
path_is_under_home "$install_log_dir" || return 1
|
||||
fi
|
||||
[ ! -L "$INSTALL_LOG" ] || return 1
|
||||
rm -f "$INSTALL_LOG" 2>/dev/null || return 1
|
||||
# Publish the already-captured stderr without opening the destination for
|
||||
# writing. `ln` fails if an attacker wins the race by creating install.log.
|
||||
ln "$uv_stderr" "$INSTALL_LOG" 2>/dev/null
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Config
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -488,10 +553,45 @@ fi
|
||||
# a Verified line with the binary name and version.
|
||||
# 3. Reformat the `- pkg==X` / `+ pkg==Y` diff into an aligned
|
||||
# "pkg X → Y" table under a single header.
|
||||
# 4. Detect whether uv actually moved any packages (those same
|
||||
# `- pkg==X` / `+ pkg==Y` lines). A same-version reinstall that still
|
||||
# bumps dependencies must report differently from a true no-op, so a
|
||||
# later grep over this raw tempfile sets UV_REPORTED_PACKAGE_CHANGES.
|
||||
# 5. Persist the raw output to a log file (see INSTALL_LOG below) so a
|
||||
# same-version dependency bump — or a failed install — can point the
|
||||
# user at the full details after the terminal scrolls away.
|
||||
# Using a tempfile (vs. process substitution) ensures we see uv's full exit
|
||||
# status and don't race the warning past later log lines.
|
||||
# status, don't race the warning past later log lines, and can re-scan the
|
||||
# raw output for (4) after the awk pass above has already reformatted it.
|
||||
uv_stderr=$(mktemp 2>/dev/null) || uv_stderr="/tmp/deepagents-install.$$.err"
|
||||
uv_rc=0
|
||||
UV_REPORTED_PACKAGE_CHANGES=false
|
||||
# Mirror uv's raw output to a persistent log under the XDG cache dir. A
|
||||
# same-version dependency bump prints only a one-line summary and a failed
|
||||
# install scrolls past, so the log preserves the full diff/errors for later.
|
||||
# Prefer $XDG_CACHE_HOME, falling back to ~/.cache. INSTALL_LOG is the real
|
||||
# path used for writes; INSTALL_LOG_DISPLAY is the tilde-collapsed form shown
|
||||
# to the user. Both stay empty when the dir can't be created, which every
|
||||
# consumer treats as "feature disabled" so messages degrade cleanly.
|
||||
INSTALL_LOG=""
|
||||
INSTALL_LOG_DISPLAY=""
|
||||
cache_root="${XDG_CACHE_HOME:-}"
|
||||
if [ "$(id -u)" -eq 0 ] && [ -n "${HOME:-}" ]; then
|
||||
cache_root="${HOME}/.cache"
|
||||
elif [ -z "$cache_root" ] && [ -n "${HOME:-}" ]; then
|
||||
cache_root="${HOME}/.cache"
|
||||
fi
|
||||
if [ -n "$cache_root" ]; then
|
||||
if install_log_dir=$(prepare_install_log_dir "$cache_root"); then
|
||||
INSTALL_LOG="${install_log_dir}/install.log"
|
||||
INSTALL_LOG_DISPLAY="$INSTALL_LOG"
|
||||
if [ -n "${HOME:-}" ]; then
|
||||
case "$INSTALL_LOG" in
|
||||
"$HOME"/*) INSTALL_LOG_DISPLAY="~${INSTALL_LOG#"$HOME"}" ;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if [[ -n "$PRERELEASE" ]]; then
|
||||
"$UV_BIN" tool install -U --python "$PYTHON_VERSION" \
|
||||
--prerelease "$PRERELEASE" "$PACKAGE" 2>"$uv_stderr" || uv_rc=$?
|
||||
@@ -570,9 +670,21 @@ if [ "$VERBOSE" != "1" ] && command -v awk >/dev/null 2>&1; then
|
||||
else
|
||||
cat "$uv_stderr" >&2
|
||||
fi
|
||||
if grep -Eq '^[[:space:]]+[-+][[:space:]]+[^=]+==' "$uv_stderr"; then
|
||||
UV_REPORTED_PACKAGE_CHANGES=true
|
||||
fi
|
||||
if [ -n "$INSTALL_LOG" ]; then
|
||||
copy_install_log || { INSTALL_LOG=""; INSTALL_LOG_DISPLAY=""; }
|
||||
fi
|
||||
rm -f "$uv_stderr"
|
||||
if [ "$uv_rc" -ne 0 ]; then
|
||||
log_error "Failed to install ${PACKAGE}. See errors above."
|
||||
# The log captured uv's full stderr (copied just above, before this exit), so
|
||||
# point the user at it — non-verbose mode trims uv's lines from the terminal
|
||||
# and piped `curl | bash` runs lose scrollback.
|
||||
if [ -n "$INSTALL_LOG" ]; then
|
||||
log_error "Full install log: ${INSTALL_LOG_DISPLAY}"
|
||||
fi
|
||||
log_error "Common fixes: check your network, try a different Python version (DEEPAGENTS_CODE_PYTHON=3.12), or install manually."
|
||||
exit 1
|
||||
fi
|
||||
@@ -582,6 +694,9 @@ if [ "$OS" = "macos" ] && [ -d "${HOME}/Library/Caches/uv" ]; then
|
||||
elif [ -d "${HOME}/.cache/uv" ]; then
|
||||
fix_owner "${HOME}/.cache/uv"
|
||||
fi
|
||||
# Restore ownership for the log path without recursively chowning a cache path
|
||||
# that could have been swapped after creation.
|
||||
fix_install_log_owner
|
||||
# ---------------------------------------------------------------------------
|
||||
# Post-install verification + contextual status
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -623,7 +738,19 @@ if [ "$IS_EDITABLE" = true ]; then
|
||||
elif [ -z "$PRE_VERSION" ]; then
|
||||
log_success "deepagents-code${NEW_VERSION:+ ${NEW_VERSION}} installed."
|
||||
elif [ -n "$NEW_VERSION" ] && [ "$PRE_VERSION" = "$NEW_VERSION" ]; then
|
||||
log_success "deepagents-code ${NEW_VERSION} already up to date."
|
||||
# Same app version, but uv may have refreshed transitive deps (security or
|
||||
# compat bumps). The final status line is the user-facing summary, so a flat
|
||||
# "already up to date" would contradict the package diff printed just above
|
||||
# (and, in non-verbose mode where an addition-only diff is suppressed, hide
|
||||
# the dep move entirely). UV_REPORTED_PACKAGE_CHANGES (set far above) is the
|
||||
# signal that the reinstall actually moved packages.
|
||||
if [ "$UV_REPORTED_PACKAGE_CHANGES" = true ]; then
|
||||
# INSTALL_LOG_DISPLAY is empty exactly when no log was written, so the
|
||||
# `:+` suffix appends the pointer only when there's a log to point at.
|
||||
log_success "deepagents-code ${NEW_VERSION} was already up to date; dependencies were updated.${INSTALL_LOG_DISPLAY:+ Details: ${INSTALL_LOG_DISPLAY}}"
|
||||
else
|
||||
log_success "deepagents-code ${NEW_VERSION} already up to date."
|
||||
fi
|
||||
elif [ -n "$NEW_VERSION" ]; then
|
||||
log_success "deepagents-code updated: ${PRE_VERSION} → ${NEW_VERSION}."
|
||||
else
|
||||
@@ -783,11 +910,15 @@ if [ "$SKIP_OPTIONAL" != "1" ]; then
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Done — footer wording depends on whether anything changed:
|
||||
# - already up to date → "Already installed"
|
||||
# Done — footer wording depends on what changed:
|
||||
# - same app version + dependency changes → "Dependencies updated"
|
||||
# - already up to date → "Already installed"
|
||||
# - fresh install / upgrade / editable→PyPI swap → "Setup complete"
|
||||
# ---------------------------------------------------------------------------
|
||||
if [ "$IS_EDITABLE" = false ] && [ -n "$PRE_VERSION" ] && [ -n "$NEW_VERSION" ] \
|
||||
&& [ "$PRE_VERSION" = "$NEW_VERSION" ] && [ "$UV_REPORTED_PACKAGE_CHANGES" = true ]; then
|
||||
footer_msg="Dependencies updated."
|
||||
elif [ "$IS_EDITABLE" = false ] && [ -n "$PRE_VERSION" ] && [ -n "$NEW_VERSION" ] \
|
||||
&& [ "$PRE_VERSION" = "$NEW_VERSION" ]; then
|
||||
footer_msg="Already installed."
|
||||
else
|
||||
|
||||
@@ -63,7 +63,7 @@ if [ "${{1:-}}" = "tool" ] && [ "${{2:-}}" = "install" ]; then
|
||||
if [ -n "${{FAKE_UV_INSTALL_STDERR:-}}" ]; then
|
||||
printf '%s\n' "$FAKE_UV_INSTALL_STDERR" >&2
|
||||
fi
|
||||
exit 0
|
||||
exit "${{FAKE_UV_INSTALL_RC:-0}}"
|
||||
fi
|
||||
printf 'unexpected uv args: %s\n' "$*" >&2
|
||||
exit 1
|
||||
@@ -112,6 +112,7 @@ def _env(
|
||||
return {
|
||||
**os.environ,
|
||||
"HOME": str(home),
|
||||
"XDG_CACHE_HOME": str(home / ".cache"),
|
||||
"PATH": f"{bin_dir}{os.pathsep}{os.environ['PATH']}",
|
||||
"UV_BIN": str(uv),
|
||||
"DEEPAGENTS_CODE_SKIP_OPTIONAL": "1",
|
||||
@@ -562,6 +563,15 @@ _REMOVAL_DIFF = (
|
||||
" - deepagents-code==0.1.18\n + deepagents-code==0.1.19\n - dropped-dep==2.0.0"
|
||||
)
|
||||
|
||||
_DEPENDENCY_UPDATE_DIFF = " - boto3==1.43.33\n + boto3==1.43.34"
|
||||
|
||||
# A pure-addition diff: uv pulled in a brand-new transitive dep without any
|
||||
# version change to an existing package.
|
||||
_DEPENDENCY_ADDITION_DIFF = " + brand-new-dep==1.0.0"
|
||||
|
||||
# uv ran but moved nothing — only timing/summary noise, no `± pkg==ver` lines.
|
||||
_NO_PACKAGE_CHANGE_STDERR = "Resolved 5 packages in 12ms\nAudited 5 packages in 1ms"
|
||||
|
||||
|
||||
def test_install_script_fresh_install_hides_packages(tmp_path: Path) -> None:
|
||||
"""A fresh install hides every dependency touched by uv."""
|
||||
@@ -608,6 +618,294 @@ def test_install_script_upgrade_still_shows_diff(tmp_path: Path) -> None:
|
||||
assert "Installed 3 packages" not in proc.stderr
|
||||
|
||||
|
||||
def test_install_script_same_version_with_dependency_updates_says_dependencies_updated(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
"""Unchanged app version + a uv dependency diff reports the deps were updated.
|
||||
|
||||
The fake `dcode -v` reports the same version before and after install, so
|
||||
`PRE_VERSION == NEW_VERSION` and the same-version branch fires; the `± pkg==`
|
||||
diff in stderr must steer it away from the flat "already up to date" message.
|
||||
Also verifies the raw uv diff is persisted to the cache install log and that
|
||||
the success line points the user at it via the `Details:` suffix.
|
||||
"""
|
||||
proc, _ = _invoke(
|
||||
tmp_path,
|
||||
{"FAKE_UV_INSTALL_STDERR": _DEPENDENCY_UPDATE_DIFF},
|
||||
installed_version="0.1.8",
|
||||
latest_version="0.1.20",
|
||||
)
|
||||
|
||||
assert proc.returncode == 0
|
||||
assert (
|
||||
"deepagents-code 0.1.8 was already up to date; dependencies were updated. "
|
||||
"Details: ~/.cache/deepagents-code/install.log"
|
||||
) in proc.stdout
|
||||
assert "deepagents-code 0.1.8 already up to date" not in proc.stdout
|
||||
assert (tmp_path / "home/.cache/deepagents-code/install.log").read_text() == (
|
||||
f"{_DEPENDENCY_UPDATE_DIFF}\n"
|
||||
)
|
||||
assert "✔ Dependencies updated. Run: dcode" in proc.stdout
|
||||
assert "✔ Already installed. Run: dcode" not in proc.stdout
|
||||
|
||||
|
||||
def test_install_script_same_version_no_dependency_changes_says_up_to_date(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
"""Unchanged app version + no uv package diff keeps the flat no-op message.
|
||||
|
||||
The negative mirror of the dependency-update test: when uv runs but moves
|
||||
nothing (only timing/summary noise), the flag must stay false so the plain
|
||||
"already up to date" message is emitted. Guards against the flag defaulting
|
||||
on, the conditional inverting, or the grep matching uv's noise lines. The
|
||||
log is still written (the no-op stderr) but the `Details:` suffix is
|
||||
suppressed, since there's no dependency change worth pointing at.
|
||||
"""
|
||||
proc, _ = _invoke(
|
||||
tmp_path,
|
||||
{"FAKE_UV_INSTALL_STDERR": _NO_PACKAGE_CHANGE_STDERR},
|
||||
installed_version="0.1.8",
|
||||
latest_version="0.1.20",
|
||||
)
|
||||
|
||||
assert proc.returncode == 0
|
||||
assert "deepagents-code 0.1.8 already up to date." in proc.stdout
|
||||
assert "dependencies were updated" not in proc.stdout
|
||||
assert "Details: ~/.cache/deepagents-code/install.log" not in proc.stdout
|
||||
assert (tmp_path / "home/.cache/deepagents-code/install.log").read_text() == (
|
||||
f"{_NO_PACKAGE_CHANGE_STDERR}\n"
|
||||
)
|
||||
assert "✔ Already installed. Run: dcode" in proc.stdout
|
||||
|
||||
|
||||
def test_install_script_same_version_with_new_dependency_says_dependencies_updated(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
"""A pure-addition diff also counts as a dependency change.
|
||||
|
||||
A new transitive dep (a `+ pkg==` line with no matching `-`) trips the flag
|
||||
just like an upgrade does, so the same-version branch reports the change
|
||||
rather than a flat no-op. Pins this `+`-only semantics deliberately, and
|
||||
verifies the addition-only diff is persisted to the install log.
|
||||
"""
|
||||
proc, _ = _invoke(
|
||||
tmp_path,
|
||||
{"FAKE_UV_INSTALL_STDERR": _DEPENDENCY_ADDITION_DIFF},
|
||||
installed_version="0.1.8",
|
||||
latest_version="0.1.20",
|
||||
)
|
||||
|
||||
assert proc.returncode == 0
|
||||
assert (
|
||||
"deepagents-code 0.1.8 was already up to date; dependencies were updated. "
|
||||
"Details: ~/.cache/deepagents-code/install.log"
|
||||
) in proc.stdout
|
||||
assert (tmp_path / "home/.cache/deepagents-code/install.log").read_text() == (
|
||||
f"{_DEPENDENCY_ADDITION_DIFF}\n"
|
||||
)
|
||||
|
||||
|
||||
def test_install_script_dependency_update_without_writable_log_omits_details(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
"""When the log dir can't be created, the message drops the `Details:` suffix.
|
||||
|
||||
Points `XDG_CACHE_HOME` under a regular file so `mkdir -p` fails, leaving
|
||||
`INSTALL_LOG` empty. The dependency-update message must still fire, just
|
||||
without a pointer to a log that was never written — guards against the
|
||||
suffix being appended unconditionally.
|
||||
"""
|
||||
blocker = tmp_path / "blocker"
|
||||
blocker.write_text("") # regular file; mkdir -p underneath must fail
|
||||
|
||||
proc, _ = _invoke(
|
||||
tmp_path,
|
||||
{
|
||||
"FAKE_UV_INSTALL_STDERR": _DEPENDENCY_UPDATE_DIFF,
|
||||
"XDG_CACHE_HOME": str(blocker / "cache"),
|
||||
},
|
||||
installed_version="0.1.8",
|
||||
latest_version="0.1.20",
|
||||
)
|
||||
|
||||
assert proc.returncode == 0
|
||||
assert (
|
||||
"deepagents-code 0.1.8 was already up to date; dependencies were updated."
|
||||
in proc.stdout
|
||||
)
|
||||
assert "Details:" not in proc.stdout
|
||||
assert not (blocker / "cache").exists()
|
||||
|
||||
|
||||
def test_install_script_dependency_update_with_failed_log_copy_omits_details(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
"""When log creation succeeds but copying fails, the message omits `Details:`."""
|
||||
if hasattr(os, "geteuid") and os.geteuid() == 0:
|
||||
pytest.skip("root can write through directory permissions")
|
||||
|
||||
cache = tmp_path / "cache"
|
||||
install_log_dir = cache / "deepagents-code"
|
||||
install_log_dir.mkdir(parents=True)
|
||||
install_log_dir.chmod(0o500)
|
||||
|
||||
try:
|
||||
proc, _ = _invoke(
|
||||
tmp_path,
|
||||
{
|
||||
"FAKE_UV_INSTALL_STDERR": _DEPENDENCY_UPDATE_DIFF,
|
||||
"XDG_CACHE_HOME": str(cache),
|
||||
},
|
||||
installed_version="0.1.8",
|
||||
latest_version="0.1.20",
|
||||
)
|
||||
finally:
|
||||
install_log_dir.chmod(0o700)
|
||||
|
||||
assert proc.returncode == 0
|
||||
assert (
|
||||
"deepagents-code 0.1.8 was already up to date; dependencies were updated."
|
||||
in proc.stdout
|
||||
)
|
||||
assert "Details:" not in proc.stdout
|
||||
assert not (install_log_dir / "install.log").exists()
|
||||
|
||||
|
||||
def test_install_script_refuses_symlinked_log_dir(tmp_path: Path) -> None:
|
||||
"""A pre-existing log-dir symlink disables the persistent install log."""
|
||||
cache = tmp_path / "cache"
|
||||
target = tmp_path / "target"
|
||||
install_log_dir = cache / "deepagents-code"
|
||||
cache.mkdir()
|
||||
target.mkdir()
|
||||
install_log_dir.symlink_to(target, target_is_directory=True)
|
||||
|
||||
proc, _ = _invoke(
|
||||
tmp_path,
|
||||
{
|
||||
"FAKE_UV_INSTALL_STDERR": _DEPENDENCY_UPDATE_DIFF,
|
||||
"XDG_CACHE_HOME": str(cache),
|
||||
},
|
||||
installed_version="0.1.8",
|
||||
latest_version="0.1.20",
|
||||
)
|
||||
|
||||
assert proc.returncode == 0
|
||||
assert (
|
||||
"deepagents-code 0.1.8 was already up to date; dependencies were updated."
|
||||
in proc.stdout
|
||||
)
|
||||
assert "Details:" not in proc.stdout
|
||||
assert not (target / "install.log").exists()
|
||||
|
||||
|
||||
def test_install_script_refuses_symlinked_log_file(tmp_path: Path) -> None:
|
||||
"""A pre-existing log-file symlink disables the persistent install log."""
|
||||
cache = tmp_path / "cache"
|
||||
install_log_dir = cache / "deepagents-code"
|
||||
target = tmp_path / "target.log"
|
||||
install_log_dir.mkdir(parents=True)
|
||||
target.write_text("keep me\n")
|
||||
(install_log_dir / "install.log").symlink_to(target)
|
||||
|
||||
proc, _ = _invoke(
|
||||
tmp_path,
|
||||
{
|
||||
"FAKE_UV_INSTALL_STDERR": _DEPENDENCY_UPDATE_DIFF,
|
||||
"XDG_CACHE_HOME": str(cache),
|
||||
},
|
||||
installed_version="0.1.8",
|
||||
latest_version="0.1.20",
|
||||
)
|
||||
|
||||
assert proc.returncode == 0
|
||||
assert (
|
||||
"deepagents-code 0.1.8 was already up to date; dependencies were updated."
|
||||
in proc.stdout
|
||||
)
|
||||
assert "Details:" not in proc.stdout
|
||||
assert target.read_text() == "keep me\n"
|
||||
|
||||
|
||||
def test_install_script_unset_xdg_cache_home_falls_back_to_home_cache(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
"""An empty `XDG_CACHE_HOME` falls back to `~/.cache` for the log path.
|
||||
|
||||
`_env` always sets `XDG_CACHE_HOME`, which would otherwise mask the
|
||||
fallback branch — the primary path on machines (e.g. macOS) that don't
|
||||
export it. Overriding it to empty exercises that branch directly.
|
||||
"""
|
||||
proc, _ = _invoke(
|
||||
tmp_path,
|
||||
{
|
||||
"FAKE_UV_INSTALL_STDERR": _DEPENDENCY_UPDATE_DIFF,
|
||||
"XDG_CACHE_HOME": "",
|
||||
},
|
||||
installed_version="0.1.8",
|
||||
latest_version="0.1.20",
|
||||
)
|
||||
|
||||
assert proc.returncode == 0
|
||||
assert (
|
||||
"deepagents-code 0.1.8 was already up to date; dependencies were updated. "
|
||||
"Details: ~/.cache/deepagents-code/install.log"
|
||||
) in proc.stdout
|
||||
assert (tmp_path / "home/.cache/deepagents-code/install.log").read_text() == (
|
||||
f"{_DEPENDENCY_UPDATE_DIFF}\n"
|
||||
)
|
||||
|
||||
|
||||
def test_install_script_log_path_outside_home_stays_absolute(tmp_path: Path) -> None:
|
||||
"""A log path outside `$HOME` is shown verbatim, not tilde-collapsed.
|
||||
|
||||
The `~` collapse only fires for paths under `$HOME`; an `XDG_CACHE_HOME`
|
||||
elsewhere must surface the absolute path in the `Details:` suffix.
|
||||
"""
|
||||
external = tmp_path / "external-cache"
|
||||
|
||||
proc, _ = _invoke(
|
||||
tmp_path,
|
||||
{
|
||||
"FAKE_UV_INSTALL_STDERR": _DEPENDENCY_UPDATE_DIFF,
|
||||
"XDG_CACHE_HOME": str(external),
|
||||
},
|
||||
installed_version="0.1.8",
|
||||
latest_version="0.1.20",
|
||||
)
|
||||
|
||||
assert proc.returncode == 0
|
||||
expected_log = external / "deepagents-code" / "install.log"
|
||||
assert f"Details: {expected_log}" in proc.stdout
|
||||
assert "Details: ~/" not in proc.stdout
|
||||
assert expected_log.read_text() == f"{_DEPENDENCY_UPDATE_DIFF}\n"
|
||||
|
||||
|
||||
def test_install_script_failed_install_points_to_log(tmp_path: Path) -> None:
|
||||
"""A failed `uv tool install` still writes the log and points the user at it.
|
||||
|
||||
The log is copied from uv's captured stderr before the failure exit, so the
|
||||
error path can hand the user the full output — the case where a persistent
|
||||
log matters most. Guards the `cp`-before-`exit` ordering.
|
||||
"""
|
||||
proc, _ = _invoke(
|
||||
tmp_path,
|
||||
{
|
||||
"FAKE_UV_INSTALL_STDERR": _DEPENDENCY_UPDATE_DIFF,
|
||||
"FAKE_UV_INSTALL_RC": "1",
|
||||
},
|
||||
installed_version="0.1.8",
|
||||
latest_version="0.1.20",
|
||||
)
|
||||
|
||||
assert proc.returncode != 0
|
||||
assert "Failed to install" in proc.stderr
|
||||
assert "Full install log: ~/.cache/deepagents-code/install.log" in proc.stderr
|
||||
assert (tmp_path / "home/.cache/deepagents-code/install.log").read_text() == (
|
||||
f"{_DEPENDENCY_UPDATE_DIFF}\n"
|
||||
)
|
||||
|
||||
|
||||
def test_install_script_upgrade_marks_removed_packages(tmp_path: Path) -> None:
|
||||
"""An upgrade that drops a transitive dependency labels it `(removed)`."""
|
||||
proc, _ = _invoke(
|
||||
|
||||
Generated
+52
@@ -439,6 +439,56 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/9d/2a/9186535ce58db529927f6cf5990a849aa9e052eea3e2cfefe20b9e1802da/bracex-2.6-py3-none-any.whl", hash = "sha256:0b0049264e7340b3ec782b5cb99beb325f36c3782a32e36e876452fd49a09952", size = 11508, upload-time = "2025-06-22T19:12:29.781Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bsdiff4"
|
||||
version = "1.2.6"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/53/b9/4559ede9a4c8c4451688303544da84654643fdc7f28790aca85be80b4b7c/bsdiff4-1.2.6.tar.gz", hash = "sha256:2ab57d01a78b39e29e5accc9cfead4130982ded9dccbc4261bd0e9c51d6b751d", size = 13259, upload-time = "2025-02-19T17:42:33.612Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/10/08/6472d5c2527688b16ad2c2dd09e324281f5e78eea5e4dba5f65a7949f39c/bsdiff4-1.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b151c28098b3c522b1735cdfe5e84e8f164f0ef4a592adb227d7a10727034673", size = 16212, upload-time = "2025-02-19T17:39:53.399Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/33/41/4d1fa5980c01faa0d5c578e41ce73b4df98cd74e33f92323880df0da035e/bsdiff4-1.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:29def064f6bcd13d0d7a82e5caa4848158b7f49c3a8fe44fbef3031456fb7dd2", size = 16031, upload-time = "2025-02-19T17:39:54.481Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/41/188f858a71eb529145b6706f8ac618fd9f719807f46e0cebe2ea482bfe78/bsdiff4-1.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6f4cf8e00116e14e9e6c3fb5747478022a27215a9a65ed223fed82d2cfbc4d3", size = 33763, upload-time = "2025-02-19T17:39:55.438Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/27/ea/84cc364a0c0f6eb3e503bf1625aa62eb411aa7474d1c91ec201812295fcb/bsdiff4-1.2.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:897a260d30acc4df9803f500682eb7951fdc104a3e155787e1e581258f38df50", size = 35705, upload-time = "2025-02-19T17:39:56.601Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fe/54/c235fd3e95aa3a4ac53de83605723a149a33eb11aff64e49488132b857f8/bsdiff4-1.2.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d994ee6113c3f030bb9f373e917f00db13c026c295fe9f314f23171935d88371", size = 33807, upload-time = "2025-02-19T17:39:57.601Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d2/8b/010d14d3ab321c1c35fc4145b020c1e76ed8a29a214ce6bcc093ddedee13/bsdiff4-1.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba5028a2aaa8e4cacb224031af9140e05d9c407ba15b59471380badcc4845777", size = 33250, upload-time = "2025-02-19T17:39:58.552Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2c/91/ae41950f7b823e8061520f3b28d47534b47f314b4148690c4a002d764bd7/bsdiff4-1.2.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1edd3069dc14cecaa804faaae776a5d14f85217c41b3180b794e5fbf684d35dd", size = 35919, upload-time = "2025-02-19T17:40:00.052Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6c/b4/f29c451e7718d4366a72f9a87a7f3cc76cb56cb5e9305eae087eab83f7a0/bsdiff4-1.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0fb562e451d5b3a7523c67ce04fe541d3a004914e5760a47116883972f5ff8bc", size = 33740, upload-time = "2025-02-19T17:40:01.893Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3a/73/004b3c4511df3df0d5e591ecd7aaf92c851b22be200283428d3577f4400b/bsdiff4-1.2.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b7309380d8edbd3d46c4ed3930f7062b793bac8f004b32139db7af7c4612e241", size = 37325, upload-time = "2025-02-19T17:40:02.911Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d9/ea/5fa1d331c4a2e73e4e90a851768749a9960cefcb443da3abaae69e891f06/bsdiff4-1.2.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f2f7504f08181227717fee04f25169d5901322c29d3fd054e4cb61bd60b3ffb4", size = 35791, upload-time = "2025-02-19T17:40:03.866Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/04/7616e8abec54562c86742c7bacaaba53c0c4733565ea00e8c5ffe2c5c9ce/bsdiff4-1.2.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:6ad599216e7ee3db5737951d06c43b8e65d5b0db5c42300e85f18d399ec0bc5e", size = 35413, upload-time = "2025-02-19T17:40:05.692Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c6/d6/3fff18a97e127cc783e02de3c934bca63fabc0d4a379e091973b006cbae6/bsdiff4-1.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cd133a9475c9dfba6243dd07f118ee58a0b7f136c00d316e2d92d3f82169bd9e", size = 32939, upload-time = "2025-02-19T17:40:06.639Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/36/32/2943637e17eca717cdd091625d4198cf7a49dd7d235944a86f1a8a6134fe/bsdiff4-1.2.6-cp311-cp311-win32.whl", hash = "sha256:403e8cc003451a8c4672c345a50aee3cf89d20983701e38fbbb67e07cb808c57", size = 18257, upload-time = "2025-02-19T17:40:07.59Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b1/f8/83f087ab62bebde26956f084ab272e19d11db5df6700f4f48d29647235fd/bsdiff4-1.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:164a059e1e07932f91d90471a4ef4dac749f2dee780f08501522805398b32ed8", size = 19530, upload-time = "2025-02-19T17:40:08.504Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/58/044dd110fb0a0160f5cacecbfb9904043c8179f8c14093e22b6d8c6b9391/bsdiff4-1.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:69c5052e94ad991c397b5a46f8eab42f2e256c42aa5677896b7a3ea9e3d06adc", size = 16267, upload-time = "2025-02-19T17:40:10.376Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/37/a1/70b74154344486bac9bf438ec309ae502f07df8cd7ca713d58f658769ff4/bsdiff4-1.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:223ae0fc9f386dcf919a09a2029c391a0f0afaf4a5892b9a6e1b622bf42e1ae5", size = 16090, upload-time = "2025-02-19T17:40:11.334Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/90/36531261d8a150fcb8193fe2ad46d939b8a91549976424852f6a2a335689/bsdiff4-1.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48ea2298a281068d82b78454ee58ac7306ed38c9af55afddb04cf796df932d63", size = 33675, upload-time = "2025-02-19T17:40:13.218Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4a/97/8b73b3684c63e88508ad308229f33a8a5be6c4762e4160f96e2a6fc46906/bsdiff4-1.2.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2534e286ef5ae58767b9b17be64742424ca1e52ec748b0d8f8e24eecd12bc28a", size = 35648, upload-time = "2025-02-19T17:40:14.296Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/39/0b1dd6494c743fa2c62bd7c35f5dec9f5802d01c1da1ef75a2e20a481ed4/bsdiff4-1.2.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ff079b0f4cf874af4b6816983557b6b9d45996f88736046653e2d2311fa1876", size = 33772, upload-time = "2025-02-19T17:40:15.341Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/23/98fc7482f957602c611203a9e485b9dbf4caf9d918e92453e3729cf5f0b4/bsdiff4-1.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56c2728c96d1d4eb8e089e4797c018a56be3f905f440fb507773f44c567fcd38", size = 33238, upload-time = "2025-02-19T17:40:16.343Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/04/c3db957b7a324a3f25f721a82c288e9abe60059a0a2d2f9b3c19fb49cdb2/bsdiff4-1.2.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9deb9b3cdb4d327e43b8c7bd11ed3707587f1183b35fb8a4c06c4f34bce62c6a", size = 35889, upload-time = "2025-02-19T17:40:18.237Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c3/a8/73d2abfd98a33cd74a0fc491e527d734c222ae18b499a10689f3adbc8d5c/bsdiff4-1.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e87c67b06ac96af6171b774dc8c03d2bde70c67c6488078eff44e0af4864acf6", size = 33606, upload-time = "2025-02-19T17:40:21.398Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/c3/713b3bb3711b62e51f6f67d6d9f63098e4d3a51d8b91e52c962f5c01a2b7/bsdiff4-1.2.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:04bb2948301ad48123d308bf2342c83cae81d7edb52d11bdde00266d89ca071e", size = 37211, upload-time = "2025-02-19T17:40:22.365Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/c5/40559695ea0bd3332c37ef8182fc0f96ceed838ae6b03ca9ddcd8cf0f7df/bsdiff4-1.2.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:43649a44fc21f017be902e19ccf7fb8bac6ef2d7f93d871bbc6bc49acec9ffee", size = 35750, upload-time = "2025-02-19T17:40:23.554Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/9b/eb4683896119ec9d26d1eb3f12efc0d8a902451f4025db12c21c5a82992a/bsdiff4-1.2.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:baa76ec557dc48847c3ed1ff5720b5095c439c868f7568da30dcabbabceb2b92", size = 35364, upload-time = "2025-02-19T17:40:24.485Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/ad/0968b67aecf00873e0e5c07e97ba2300594505d4dbce62702b9f56a62d66/bsdiff4-1.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:701168e2931da777e6e72ae17f22eb519e9ce25ec5108d149c9da7b3b80e1184", size = 32831, upload-time = "2025-02-19T17:40:25.571Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6c/18/adfcf72780f19cea1fe9948cbfb49890599424e94c752bf7d614093c0fc5/bsdiff4-1.2.6-cp312-cp312-win32.whl", hash = "sha256:f9f2e5e716d35af3252f69a15afc2b166970c98596a1114af4c6d2834fe8e871", size = 18308, upload-time = "2025-02-19T17:40:26.571Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9d/5d/31672172bb4566c1f1187fa28a1437125d4b5106bc55f9f7b9a75371094c/bsdiff4-1.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:0b29568d1e33e32ea075c12a696b32e4d6cea344d0270a2292075254efd86014", size = 19553, upload-time = "2025-02-19T17:40:27.592Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4f/56/887d90b0e52ce7b5533a6f1390ab9a68215a70ba34848441730e215ffc1c/bsdiff4-1.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a98d7975a670fc360d894ef2ec00294e6b7b19790c58457e40c8a5d57a1865b0", size = 16260, upload-time = "2025-02-19T17:40:28.614Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/4c/825a16932605d305501ed144ae5567a3dc90c9164a393c61cc0ed68df3f0/bsdiff4-1.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ee4417341712a4bf736694ce9ad3902b8c6fbd3425aadca44df9b66a51bbefa4", size = 16080, upload-time = "2025-02-19T17:40:29.612Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/e2/0cf538a786f47b08e26f3970a6f98c2b7b9d555c01e085425282944a2c7f/bsdiff4-1.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39ddfa2137de44c9743a611d71d263d0cc8c45e5b18ee84ca5ff6b6240be1740", size = 33664, upload-time = "2025-02-19T17:40:31.646Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1f/c0/44ac255f1d16865e39ef941470e30bb5c362dd216b62837bb13880d1dd36/bsdiff4-1.2.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6474d8f34f89d25fa1803c639cc8ed49121752a56a15b4cd21e9267154cdaf70", size = 35648, upload-time = "2025-02-19T17:40:32.793Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/6b/d5871af38cbb8527652b65463c3dd736b6250828d8d6daf48be712a2ebfe/bsdiff4-1.2.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f8e9c876929c03ef5d448e2626e8b2961040c3a9f0dd3d483643dbccd0e7ff7a", size = 33792, upload-time = "2025-02-19T17:40:35.498Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/1e/7027849a6dc02b580e352b1528899053bd919029b185fbaa14c6f268180b/bsdiff4-1.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46313f0eb8f63efb54a3c4219cd7b5b8a7795012b535f9d0838fe3f2b3349849", size = 33238, upload-time = "2025-02-19T17:40:37.165Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/97/df/c4a3e2bb1c1f9f09c2c5f8a9025c67f5ec7fcc8949338e54cb2d4fba9009/bsdiff4-1.2.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6b5757b1a83829f00ef34953c6865ea82e9c71126e465bc32d029c55da9e45b", size = 35866, upload-time = "2025-02-19T17:40:38.789Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/83/03/76a5aaaa0ccc282b239b3f148f6dd6033d37f79c1d1a89846b712224d132/bsdiff4-1.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:734552992ecc86749a8ef55d03f999f9a47576cc609d7d4d9a7aec274b43ee4d", size = 33688, upload-time = "2025-02-19T17:40:39.762Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/b3/b240d4840a16d923c60e8e9eacf0777cf9378e30610037f6c85324daea85/bsdiff4-1.2.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:853c3221daac6f8d347f12eb0b73ca9dbb7db483e7b5f40b1e2fbb05730645a7", size = 37273, upload-time = "2025-02-19T17:40:41.626Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/84/2223a09c4950a3e419ce94eb0af6d90c1ee562b9962ef2d72515f4ad6271/bsdiff4-1.2.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:94526dc11e56f330c2f4b1e2e9389b958a7891f6c86b5aac83bd9c7a90eb088a", size = 35844, upload-time = "2025-02-19T17:40:42.646Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/18/7b/c02f703b449feb20b245eb803e7d446508b80d5b4065d1eb9cc75d02ae3b/bsdiff4-1.2.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f5474e1d9253564ed0823e2685a403d9dfdbba3c7b70a80f5066d61427848253", size = 35418, upload-time = "2025-02-19T17:40:44.562Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/eb/52/623ee28011b6935f0dfe67397ec27c2a900b9f0bda1b1ec2a5b174c53fb7/bsdiff4-1.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5529731ac88151345a8bb76dad4fdb218af10a8a505161d1aa3d669e49cb7b77", size = 32892, upload-time = "2025-02-19T17:40:45.552Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/6c/e740e347bb46ea08ceacf39df56c2ffd2bd20b95d458409ea303fbf2b946/bsdiff4-1.2.6-cp313-cp313-win32.whl", hash = "sha256:c8089827c41b37f7c9192492742289929097c5ab2a6b3a120919fee27fbc01b8", size = 18304, upload-time = "2025-02-19T17:40:47.37Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/d1/9be6f6124afab9837db1ffc5801ca1aa86f2077d4224ff729e88fabada71/bsdiff4-1.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:37ff935ba714e0726584dad2bc4c063218b588b110115e8554ebc438ee7bccf3", size = 19543, upload-time = "2025-02-19T17:40:48.369Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "build"
|
||||
version = "1.5.0"
|
||||
@@ -2940,6 +2990,7 @@ name = "langchain-quickjs"
|
||||
version = "0.3.0"
|
||||
source = { editable = "../partners/quickjs" }
|
||||
dependencies = [
|
||||
{ name = "bsdiff4" },
|
||||
{ name = "deepagents" },
|
||||
{ name = "langchain" },
|
||||
{ name = "langchain-core" },
|
||||
@@ -2949,6 +3000,7 @@ dependencies = [
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "bsdiff4", specifier = ">=1.2.6,<2.0.0" },
|
||||
{ name = "deepagents", editable = "../deepagents" },
|
||||
{ name = "langchain", specifier = ">=1.3.9,<2.0.0" },
|
||||
{ name = "langchain-core", specifier = ">=1.4.7,<2.0.0" },
|
||||
|
||||
Reference in New Issue
Block a user