Compare commits
2 Commits
main
...
8dc3ae88b3
| Author | SHA1 | Date | |
|---|---|---|---|
|
8dc3ae88b3
|
|||
|
a177877ce3
|
@@ -12,11 +12,11 @@ Browser: Firefox 🦊 (actually [Zen Browser](https://github.com/zen-browser/des
|
||||
|
||||
Text Editor: [Doom Emacs](https://github.com/doomemacs/doomemacs)
|
||||
|
||||
Terminal: [ghostty](https://ghostty.org/)
|
||||
Terminal: [alacritty](https://github.com/alacritty/alacritty)
|
||||
|
||||
Shell: [fish](https://fishshell.com/) with the [pure](https://github.com/pure-fish/pure) prompt
|
||||
|
||||
WM: [niri](https://github.com/YaLTeR/niri)
|
||||
WM: [niri](https://github.com/YaLTeR/niri) (KDE on my desktop)
|
||||
|
||||
### Background
|
||||
- Got my background from [here](https://old.reddit.com/r/celestegame/comments/11dtgwg/all_most_of_the_backgrounds_in_celeste_edited/) and used the command `magick input.png -filter Point -resize 2880x1920! output.png` to upscale it bilinearly
|
||||
|
||||
114
flake.lock
generated
114
flake.lock
generated
@@ -109,11 +109,11 @@
|
||||
"cachyos-kernel": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1776881435,
|
||||
"narHash": "sha256-j8AobLjMzeKJugseObrVC4O5k7/aZCWoft2sCS3jWYs=",
|
||||
"lastModified": 1776608760,
|
||||
"narHash": "sha256-ehDv8bF7k/2Kf4b8CCoSm51U/MOoFuLsRXqe5wZ57sE=",
|
||||
"owner": "CachyOS",
|
||||
"repo": "linux-cachyos",
|
||||
"rev": "1c61dfd1c3ad7762faa0db8b06c6af6c59cc4340",
|
||||
"rev": "7e06e29005853bbaaa3b1c1067f915d6e0db728a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -125,11 +125,11 @@
|
||||
"cachyos-kernel-patches": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1777002108,
|
||||
"narHash": "sha256-PIZCIf6xUTOUqLFbEGH0mSwu2O/YfeAmYlgdAbP4dhs=",
|
||||
"lastModified": 1776792814,
|
||||
"narHash": "sha256-39dlIhz9KxUNQFxGpE9SvCviaOWAivdW0XJM8RnPNmg=",
|
||||
"owner": "CachyOS",
|
||||
"repo": "kernel-patches",
|
||||
"rev": "46476ae2538db486462aef8a9de37d19030cdaf2",
|
||||
"rev": "d7d558d0b2e239e27b40bcf1af6fe12e323aa391",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -222,11 +222,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1777138175,
|
||||
"narHash": "sha256-UrexPU1xQ/qB0qCjuTeljQOCDmjeCNuipZMBv3FyoJM=",
|
||||
"lastModified": 1776967792,
|
||||
"narHash": "sha256-O3YfkXQz8P2kec6Ani8fmuXvuXRAyl5/qPdt0kDNFWk=",
|
||||
"owner": "nix-community",
|
||||
"repo": "emacs-overlay",
|
||||
"rev": "d7d0c87d15148472eef847dfe298095ef4298dc1",
|
||||
"rev": "0041dd571ebebe8fa779b940fb13b6d447a48b87",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -266,11 +266,11 @@
|
||||
},
|
||||
"locked": {
|
||||
"dir": "pkgs/firefox-addons",
|
||||
"lastModified": 1777089773,
|
||||
"narHash": "sha256-ZIlNuebeWTncyl7mcV9VbceSLAaZki+UeXLPQG959xI=",
|
||||
"lastModified": 1776916994,
|
||||
"narHash": "sha256-FgqUwRZ2bwbE5w1bCUv9MB3gvwqZ4oEyCgZ6z/6jdTY=",
|
||||
"owner": "rycee",
|
||||
"repo": "nur-expressions",
|
||||
"rev": "402ba229617a12d918c2a887a4c83a9a24f9a36c",
|
||||
"rev": "a2236006e5c70e2fc06e9acb016b1ac9c0fd5935",
|
||||
"type": "gitlab"
|
||||
},
|
||||
"original": {
|
||||
@@ -484,11 +484,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1777151655,
|
||||
"narHash": "sha256-Th3a5OZyEy4kCoyLfefnt+2dwRIrFQqYgMsayF9qzFw=",
|
||||
"lastModified": 1776964438,
|
||||
"narHash": "sha256-AF0cby9Xuijr5qaFpYKbm1mExV956Hk233bel6QxpFw=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "6f59831b23d03bbf4fbd13ad167ae25da294cc14",
|
||||
"rev": "e09259dd2e147d35ef889784b51e89b0a10ffe15",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -564,11 +564,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1777132364,
|
||||
"narHash": "sha256-qK6A0xRDAgLf8DUHpDWpVL6NcWi4IhoVClcov+GjLP0=",
|
||||
"lastModified": 1776962372,
|
||||
"narHash": "sha256-Y2imW4kyIhupx8myNSeNCzDbEx2X+h+AmhNjWXA/7Yw=",
|
||||
"owner": "Jovian-Experiments",
|
||||
"repo": "Jovian-NixOS",
|
||||
"rev": "7ae8615cc307c282555b025f88e0c8d7c185bcbf",
|
||||
"rev": "ee3a1184a978e311194a2d3d352c5e6aba67a4b5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -631,11 +631,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1777066729,
|
||||
"narHash": "sha256-f+a+ikbq0VS6RQFf+A6EuVnsWYn2RR3ggRJNkzZgMto=",
|
||||
"lastModified": 1776955347,
|
||||
"narHash": "sha256-VCPA/1RWMZggfXjpMcEMC2QfDrYp6eHgqvsPfDSKGSI=",
|
||||
"owner": "TheTom",
|
||||
"repo": "llama-cpp-turboquant",
|
||||
"rev": "11a241d0db78a68e0a5b99fe6f36de6683100f6a",
|
||||
"rev": "67559e580b10e4e47e9a6fd6218873997976886d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -657,11 +657,11 @@
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1777154498,
|
||||
"narHash": "sha256-700kin0o6CoNWkg2w5+2hV1wxECeoMRCQjOerBlWleA=",
|
||||
"lastModified": 1776966087,
|
||||
"narHash": "sha256-P+39paxTvpYiMv5wqGKte7YbmxJKoihcXssV1IhkSAo=",
|
||||
"owner": "numtide",
|
||||
"repo": "llm-agents.nix",
|
||||
"rev": "013ae4bdac7d0f968174d660aeb0760a025f09d0",
|
||||
"rev": "547d51c282c15a7c9b86c8388a1adb1695b1df59",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -704,11 +704,11 @@
|
||||
"xwayland-satellite-unstable": "xwayland-satellite-unstable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1777130270,
|
||||
"narHash": "sha256-AgOIR3O+hLkTe/spgYjp0knc37iy/A5DqGRY+8DP3LE=",
|
||||
"lastModified": 1776879043,
|
||||
"narHash": "sha256-M9RjuowtoqQbFRdQAm2P6GjFwgHjRcnWYcB7ChSjDms=",
|
||||
"owner": "sodiboo",
|
||||
"repo": "niri-flake",
|
||||
"rev": "e43ef13f23c2c7ae5b10e842745cb345faff4f40",
|
||||
"rev": "535ebbe038039215a5d1c6c0c67f833409a5be96",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -737,11 +737,11 @@
|
||||
"niri-unstable": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1777115961,
|
||||
"narHash": "sha256-ehSMsSpE+0k8r+2Vseu8kangsYxToZv3vinynsDp9zs=",
|
||||
"lastModified": 1776853441,
|
||||
"narHash": "sha256-mSxfoEs7DiDhMCBzprI/1K7UXzMISuGq0b7T06LVJXE=",
|
||||
"owner": "YaLTeR",
|
||||
"repo": "niri",
|
||||
"rev": "8ed0da44d974c32c6877d2f4630c314da0717ecb",
|
||||
"rev": "74d2b18603366b98ec9045ecf4a632422f472365",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -761,11 +761,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1777140538,
|
||||
"narHash": "sha256-2y5SwHxTOwEdr8WZv1IGBVoJM47YcomfoxFnZj9TgN0=",
|
||||
"lastModified": 1776796985,
|
||||
"narHash": "sha256-cNFg3H09sBZl1v9ds6PDHfLCUTDJbefGMSv+WxFs+9c=",
|
||||
"owner": "xddxdd",
|
||||
"repo": "nix-cachyos-kernel",
|
||||
"rev": "ce6083d35e50516dd6eb6156d0cbda67baed9117",
|
||||
"rev": "ac5956bbceb022998fc1dd0001322f10ef1e6dda",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -846,11 +846,11 @@
|
||||
"systems": "systems_7"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1777001712,
|
||||
"narHash": "sha256-9JX9msZU1NvHzjKM24PRorP76Ge8GBy6LAkJKA21mlY=",
|
||||
"lastModified": 1776915193,
|
||||
"narHash": "sha256-bYyOT3OIWIKvDV+pOVd0hdCEG8orf85QX4b21LWUSEs=",
|
||||
"owner": "Infinidoge",
|
||||
"repo": "nix-minecraft",
|
||||
"rev": "394d3bfd943458baf29e4798bc9b256d824a3bb9",
|
||||
"rev": "40c972ce0f45b8c05bf245d5065647b17552312c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -861,11 +861,11 @@
|
||||
},
|
||||
"nixos-hardware": {
|
||||
"locked": {
|
||||
"lastModified": 1776983936,
|
||||
"narHash": "sha256-ZOQyNqSvJ8UdrrqU1p7vaFcdL53idK+LOM8oRWEWh6o=",
|
||||
"lastModified": 1776830795,
|
||||
"narHash": "sha256-PAfvLwuHc1VOvsLcpk6+HDKgMEibvZjCNvbM1BJOA7o=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixos-hardware",
|
||||
"rev": "2096f3f411ce46e88a79ae4eafcfc9df8ed41c61",
|
||||
"rev": "72674a6b5599e844c045ae7449ba91f803d44ebc",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -877,11 +877,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1776877367,
|
||||
"narHash": "sha256-EHq1/OX139R1RvBzOJ0aMRT3xnWyqtHBRUBuO1gFzjI=",
|
||||
"lastModified": 1776548001,
|
||||
"narHash": "sha256-ZSK0NL4a1BwVbbTBoSnWgbJy9HeZFXLYQizjb2DPF24=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "0726a0ecb6d4e08f6adced58726b95db924cef57",
|
||||
"rev": "b12141ef619e0a9c1c84dc8c684040326f27cdcc",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -991,11 +991,11 @@
|
||||
"noctalia-qs": "noctalia-qs"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1777079905,
|
||||
"narHash": "sha256-TvYEXwkZnRFQRuFyyqTNSfPnU2tMdhtiBOXSk2AWLJA=",
|
||||
"lastModified": 1776888984,
|
||||
"narHash": "sha256-Up2F/eoMuPUsZnPVYdH5TMHe1TBP2Ue1QuWd0vWZoxY=",
|
||||
"owner": "noctalia-dev",
|
||||
"repo": "noctalia-shell",
|
||||
"rev": "a50c92167c8d438000270f7eca36f6eea74f388e",
|
||||
"rev": "2c1808f9f8937fc0b82c54af513f7620fec56d71",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1133,11 +1133,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1777086717,
|
||||
"narHash": "sha256-vEl3cGHRxEFdVNuP9PbrhAWnmU98aPOLGy9/1JXzSuM=",
|
||||
"lastModified": 1776914043,
|
||||
"narHash": "sha256-qug5r56yW1qOsjSI99l3Jm15JNT9CvS2otkXNRNtrPI=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "3be56bd430bfd65d3c468a50626c3a601c7dee03",
|
||||
"rev": "2d35c4358d7de3a0e606a6e8b27925d981c01cc3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1190,11 +1190,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1777000965,
|
||||
"narHash": "sha256-xcrhVgfI13s1WH4hg5MLL83zAp6/htfF8Pjw4RPiKM8=",
|
||||
"lastModified": 1776912132,
|
||||
"narHash": "sha256-UDR6PtHacMhAQJ8SPNbPROaxbtl2Pgjww0TzipTsTZE=",
|
||||
"owner": "nix-community",
|
||||
"repo": "srvos",
|
||||
"rev": "7ae6f096b2ffbd25d17da8a4d0fe299a164c4eac",
|
||||
"rev": "e9ff039a72ff2c06271d5002eb431c443abf69fa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1356,11 +1356,11 @@
|
||||
"trackerlist": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1777154980,
|
||||
"narHash": "sha256-zEJCVDBjo0SDlYOnkfi9o6lJWpMfmmR6Oh67RPybbqI=",
|
||||
"lastModified": 1776895782,
|
||||
"narHash": "sha256-iHdp9lRoV3ejsTC96z7Pns/JvQKWyp+V0fdVcVOv8Xw=",
|
||||
"owner": "ngosang",
|
||||
"repo": "trackerslist",
|
||||
"rev": "9599dfb9be9d899bb5abd40a5dc53e5c5be90fd4",
|
||||
"rev": "e1a89caab7d4c5af3870a49ddc494cda745b236e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1524,11 +1524,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1777138694,
|
||||
"narHash": "sha256-yjAFuyqQyOtQ5entLYmSRf/1L0kuSDWQndS2QNBLQlc=",
|
||||
"lastModified": 1776922304,
|
||||
"narHash": "sha256-T1r7GWzeqX0C6YauIMN6D0sdr5voDAPMg8jvn59Wm7g=",
|
||||
"owner": "0xc000022070",
|
||||
"repo": "zen-browser-flake",
|
||||
"rev": "5ceb2bfc5671bfca6b1b363669309d6871043d66",
|
||||
"rev": "91cc9ed57a893b2e944de60812511f05fd408ce6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
{
|
||||
imports = [
|
||||
./no-gui.nix
|
||||
../progs/ghostty.nix
|
||||
# ../progs/ghostty.nix
|
||||
../progs/alacritty.nix
|
||||
../progs/emacs.nix
|
||||
# ../progs/trezor.nix # - broken
|
||||
../progs/flatpak.nix
|
||||
|
||||
131
home/progs/alacritty.nix
Normal file
131
home/progs/alacritty.nix
Normal file
@@ -0,0 +1,131 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
home.sessionVariables = {
|
||||
TERMINAL = "alacritty";
|
||||
};
|
||||
|
||||
programs.alacritty = {
|
||||
enable = true;
|
||||
package = pkgs.alacritty;
|
||||
settings = {
|
||||
# some programs can't handle alacritty
|
||||
env.TERM = "xterm-256color";
|
||||
|
||||
window = {
|
||||
# using a window manager, no decorations needed
|
||||
decorations = "none";
|
||||
|
||||
# semi-transparent
|
||||
opacity = 0.90;
|
||||
|
||||
# padding between the content of the terminal and the edge
|
||||
padding = {
|
||||
x = 10;
|
||||
y = 10;
|
||||
};
|
||||
|
||||
dimensions = {
|
||||
columns = 80;
|
||||
lines = 40;
|
||||
};
|
||||
};
|
||||
|
||||
scrolling = {
|
||||
history = 1000;
|
||||
multiplier = 3;
|
||||
};
|
||||
|
||||
font =
|
||||
let
|
||||
baseFont = {
|
||||
family = "JetBrains Mono Nerd Font";
|
||||
style = "Regular";
|
||||
};
|
||||
in
|
||||
{
|
||||
size = 12;
|
||||
|
||||
normal = baseFont;
|
||||
|
||||
bold = baseFont // {
|
||||
style = "Bold";
|
||||
};
|
||||
|
||||
italic = baseFont // {
|
||||
style = "Italic";
|
||||
};
|
||||
|
||||
offset.y = 0;
|
||||
glyph_offset.y = 0;
|
||||
};
|
||||
|
||||
# color scheme
|
||||
colors =
|
||||
let
|
||||
normal = {
|
||||
black = "0x1b1e28";
|
||||
red = "0xd0679d";
|
||||
green = "0x5de4c7";
|
||||
yellow = "0xfffac2";
|
||||
blue = "#435c89";
|
||||
magenta = "0xfcc5e9";
|
||||
cyan = "0xadd7ff";
|
||||
white = "0xffffff";
|
||||
};
|
||||
|
||||
bright = {
|
||||
black = "0xa6accd";
|
||||
red = normal.red;
|
||||
green = normal.green;
|
||||
yellow = normal.yellow;
|
||||
blue = normal.cyan;
|
||||
magenta = "0xfae4fc";
|
||||
cyan = "0x89ddff";
|
||||
white = normal.white;
|
||||
};
|
||||
in
|
||||
{
|
||||
inherit normal bright;
|
||||
primary = {
|
||||
background = "0x131621";
|
||||
foreground = bright.black;
|
||||
};
|
||||
|
||||
cursor = {
|
||||
text = "CellBackground";
|
||||
cursor = "CellForeground";
|
||||
};
|
||||
|
||||
search =
|
||||
let
|
||||
foreground = normal.black;
|
||||
background = normal.cyan;
|
||||
in
|
||||
{
|
||||
matches = {
|
||||
inherit foreground background;
|
||||
};
|
||||
|
||||
focused_match = {
|
||||
inherit foreground background;
|
||||
};
|
||||
};
|
||||
|
||||
selection = {
|
||||
text = "CellForeground";
|
||||
background = "0x303340";
|
||||
};
|
||||
|
||||
vi_mode_cursor = {
|
||||
text = "CellBackground";
|
||||
cursor = "CellForeground";
|
||||
};
|
||||
};
|
||||
|
||||
cursor = {
|
||||
style = "Underline";
|
||||
vi_mode_style = "Underline";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,64 +1,12 @@
|
||||
{ ... }:
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
# https://mynixos.com/home-manager/option/programs.ghostty
|
||||
programs.ghostty = {
|
||||
enable = true;
|
||||
enableFishIntegration = true;
|
||||
|
||||
# custom palette ported verbatim from the previous alacritty config
|
||||
# (poimandres-ish). lives in ~/.config/ghostty/themes/poimandres and is
|
||||
# selected by `theme = "poimandres"` below.
|
||||
themes.poimandres = {
|
||||
palette = [
|
||||
"0=#1b1e28"
|
||||
"1=#d0679d"
|
||||
"2=#5de4c7"
|
||||
"3=#fffac2"
|
||||
"4=#435c89"
|
||||
"5=#fcc5e9"
|
||||
"6=#add7ff"
|
||||
"7=#ffffff"
|
||||
"8=#a6accd"
|
||||
"9=#d0679d"
|
||||
"10=#5de4c7"
|
||||
"11=#fffac2"
|
||||
"12=#add7ff"
|
||||
"13=#fae4fc"
|
||||
"14=#89ddff"
|
||||
"15=#ffffff"
|
||||
];
|
||||
background = "131621";
|
||||
foreground = "a6accd";
|
||||
cursor-color = "a6accd";
|
||||
cursor-text = "131621";
|
||||
selection-background = "303340";
|
||||
selection-foreground = "a6accd";
|
||||
};
|
||||
|
||||
settings = {
|
||||
theme = "poimandres";
|
||||
|
||||
# font
|
||||
font-family = "JetBrainsMono Nerd Font";
|
||||
font-size = 12;
|
||||
|
||||
# window
|
||||
window-decoration = false;
|
||||
window-padding-x = 10;
|
||||
window-padding-y = 10;
|
||||
window-width = 80;
|
||||
window-height = 40;
|
||||
|
||||
# semi-transparent background
|
||||
background-opacity = 0.90;
|
||||
|
||||
# cursor
|
||||
cursor-style = "underline";
|
||||
|
||||
# keep one daemon alive so subsequent launches (e.g. niri Mod+T) are
|
||||
# instant instead of paying GTK + wgpu init each time. relies on the
|
||||
# dbus-activated systemd user service that the HM module wires up.
|
||||
gtk-single-instance = true;
|
||||
theme = "Adventure";
|
||||
background-opacity = 0.7;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -115,12 +115,8 @@ in
|
||||
|
||||
"Mod+O".action = toggle-overview;
|
||||
|
||||
# open a terminal — pass --working-directory=home so the gtk-single-instance
|
||||
# daemon doesn't keep handing back whatever cwd the focused window has.
|
||||
"Mod+T".action = spawn [
|
||||
config.home.sessionVariables.TERMINAL
|
||||
"--working-directory=home"
|
||||
];
|
||||
# open a terminal
|
||||
"Mod+T".action = spawn config.home.sessionVariables.TERMINAL;
|
||||
|
||||
# lock the screen
|
||||
"Mod+X".action = spawn (lib.getExe pkgs.swaylock);
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
};
|
||||
wallpaper = {
|
||||
enabled = true;
|
||||
skipStartupTransition = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -37,21 +37,8 @@ let
|
||||
in
|
||||
{
|
||||
home.packages = [
|
||||
# `bun2nix.hook` sets `patchPhase = bunPatchPhase`, which only runs `patchShebangs` and
|
||||
# silently ignores the standard `patches` attribute. Apply patches via `prePatch` instead
|
||||
# so they actually take effect. Tracking: nothing upstream yet.
|
||||
(inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.omp.overrideAttrs (old: {
|
||||
prePatch =
|
||||
(old.prePatch or "")
|
||||
+ ''
|
||||
# 0001 — retry without strict tools when DeepSeek (via OpenRouter) rejects strict-mode
|
||||
# `anyOf` nullable unions with `Invalid tool parameters schema : field \`anyOf\`:
|
||||
# missing field \`type\``.
|
||||
patch -p1 < ${../../patches/omp/0001-openai-completions-retry-without-strict-on-deepseek-openrouter.patch}
|
||||
# 0002 — require `reasoning_content` for OpenRouter reasoning models so DeepSeek V4 Pro
|
||||
# et al. accept follow-up requests in thinking mode.
|
||||
patch -p1 < ${../../patches/omp/0002-openai-completions-stub-reasoning-content-for-openrouter.patch}
|
||||
'';
|
||||
patches = (old.patches or [ ]) ++ [ ];
|
||||
}))
|
||||
];
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@
|
||||
# 6.12 LTS until 2027-03. Kernel 6.18 causes a reproducible ZFS deadlock
|
||||
# in dbuf_evict due to page allocator changes (__free_frozen_pages).
|
||||
# https://github.com/openzfs/zfs/issues/18426
|
||||
kernelPackages = pkgs.linuxPackages_6_12;
|
||||
kernelPackages = pkgs.linuxPackages_6_18;
|
||||
|
||||
loader = {
|
||||
# Use the systemd-boot EFI boot loader.
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
];
|
||||
};
|
||||
|
||||
services.kmscon.enable = true;
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
doas-sudo-shim
|
||||
];
|
||||
|
||||
@@ -20,7 +20,14 @@ let
|
||||
arcMaxBytes = (totalRamBytes - totalHugepageBytes) * 60 / 100;
|
||||
in
|
||||
{
|
||||
boot.zfs.package = pkgs.zfs_2_4;
|
||||
# remove inline dbuf_evict_one call so the dedicated eviction thread
|
||||
# handles cache pressure instead of stalling txg_sync on 6.14+.
|
||||
# https://github.com/openzfs/zfs/issues/18426
|
||||
boot.zfs.package = pkgs.zfs_2_4.overrideAttrs (old: {
|
||||
patches = (old.patches or [ ]) ++ [
|
||||
../patches/zfs/0001-remove-dbuf_evict_one-call.patch
|
||||
];
|
||||
});
|
||||
boot.initrd.kernelModules = [ "zfs" ];
|
||||
|
||||
boot.kernelParams = [
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
Subject: [PATCH] fix(openai-completions): retry without strict tools for DeepSeek-via-OpenRouter anyOf rejections
|
||||
|
||||
The retry-on-strict-tool-error path in openai-completions failed to recover when
|
||||
DeepSeek (and similar backends fronted by OpenRouter) reject strict-mode tool
|
||||
schemas with errors of the form:
|
||||
|
||||
Invalid tool parameters schema : field `anyOf`: missing field `type`
|
||||
|
||||
Two reasons:
|
||||
|
||||
1. Retry only triggered in "all_strict" mode. OpenRouter defaults to "mixed"
|
||||
(per-tool strict), so the early return prevented retry.
|
||||
2. The error-message regex required "strict" near "tool". DeepSeek's message
|
||||
never mentions "strict".
|
||||
|
||||
Fix:
|
||||
- Allow retry whenever any tool was sent with strict (i.e. mode != "none").
|
||||
- Recognize "Invalid tool parameters" in the regex.
|
||||
|
||||
Includes a regression test reproducing the exact DeepSeek error body via
|
||||
OpenRouter mixed-strict mode.
|
||||
|
||||
Applies cleanly against v14.2.1.
|
||||
|
||||
---
|
||||
diff --git a/packages/ai/src/providers/openai-completions.ts b/packages/ai/src/providers/openai-completions.ts
|
||||
index e58189607..3c20631c1 100644
|
||||
--- a/packages/ai/src/providers/openai-completions.ts
|
||||
+++ b/packages/ai/src/providers/openai-completions.ts
|
||||
@@ -1245,7 +1245,10 @@ function shouldRetryWithoutStrictTools(
|
||||
toolStrictMode: AppliedToolStrictMode,
|
||||
tools: Tool[] | undefined,
|
||||
): boolean {
|
||||
- if (!tools || tools.length === 0 || toolStrictMode !== "all_strict") {
|
||||
+ // Retry whenever any tool was sent with `strict: true`. OpenRouter routes to underlying
|
||||
+ // providers (e.g. DeepSeek) whose schema validators reject the strict-mode `anyOf` shape
|
||||
+ // even when omp emitted strict per-tool ("mixed"), not just provider-wide ("all_strict").
|
||||
+ if (!tools || tools.length === 0 || toolStrictMode === "none") {
|
||||
return false;
|
||||
}
|
||||
const status = extractHttpStatusFromError(error) ?? capturedErrorResponse?.status;
|
||||
@@ -1255,7 +1258,14 @@ function shouldRetryWithoutStrictTools(
|
||||
const messageParts = [error instanceof Error ? error.message : undefined, capturedErrorResponse?.bodyText]
|
||||
.filter((value): value is string => typeof value === "string" && value.trim().length > 0)
|
||||
.join("\n");
|
||||
- return /wrong_api_format|mixed values for 'strict'|tool[s]?\b.*strict|\bstrict\b.*tool/i.test(messageParts);
|
||||
+ // Patterns:
|
||||
+ // - `wrong_api_format`, `mixed values for 'strict'`: OpenAI rejecting mixed strict flags.
|
||||
+ // - `tool ... strict` / `strict ... tool`: generic strict-tool complaints.
|
||||
+ // - `Invalid tool parameters schema`: DeepSeek (via OpenRouter) rejecting strict-mode
|
||||
+ // nullable unions because their validator demands `type` alongside `anyOf`.
|
||||
+ return /wrong_api_format|mixed values for 'strict'|tool[s]?\b.*strict|\bstrict\b.*tool|invalid tool parameters/i.test(
|
||||
+ messageParts,
|
||||
+ );
|
||||
}
|
||||
|
||||
function mapStopReason(reason: ChatCompletionChunk.Choice["finish_reason"] | string): {
|
||||
diff --git a/packages/ai/test/openai-tool-strict-mode.test.ts b/packages/ai/test/openai-tool-strict-mode.test.ts
|
||||
index 2bf17e6d8..24d5a09d5 100644
|
||||
--- a/packages/ai/test/openai-tool-strict-mode.test.ts
|
||||
+++ b/packages/ai/test/openai-tool-strict-mode.test.ts
|
||||
@@ -231,6 +231,64 @@ describe("OpenAI tool strict mode", () => {
|
||||
expect(result.content).toContainEqual({ type: "text", text: "Hello" });
|
||||
expect(strictFlags).toEqual([[true], [false]]);
|
||||
});
|
||||
+ it("retries with non-strict tool schemas when OpenRouter backend rejects strict anyOf nullable unions", async () => {
|
||||
+ // Reproduces deepseek/deepseek-v4-pro via OpenRouter rejecting the strict-mode schema with:
|
||||
+ // 400 Provider returned error
|
||||
+ // {"error":{"message":"Invalid tool parameters schema : field `anyOf`: missing field `type`",...}}
|
||||
+ // OpenRouter is in mixed-strict mode by default (per-tool strict), so the original retry condition
|
||||
+ // (only "all_strict") prevented recovery. The retry now triggers whenever any tool sent strict=true.
|
||||
+ const model = getBundledModel("openrouter", "deepseek/deepseek-v3.2") as Model<"openai-completions">;
|
||||
+ const strictFlags: boolean[][] = [];
|
||||
+ global.fetch = Object.assign(
|
||||
+ async (_input: string | URL | Request, init?: RequestInit): Promise<Response> => {
|
||||
+ const bodyText = typeof init?.body === "string" ? init.body : "";
|
||||
+ const payload = JSON.parse(bodyText) as {
|
||||
+ tools?: Array<{ function?: { strict?: boolean } }>;
|
||||
+ };
|
||||
+ strictFlags.push((payload.tools ?? []).map(tool => tool.function?.strict === true));
|
||||
+ if (strictFlags.length === 1) {
|
||||
+ return new Response(
|
||||
+ JSON.stringify({
|
||||
+ error: {
|
||||
+ message: "Invalid tool parameters schema : field `anyOf`: missing field `type`",
|
||||
+ type: "invalid_request_error",
|
||||
+ param: null,
|
||||
+ code: "invalid_request_error",
|
||||
+ },
|
||||
+ }),
|
||||
+ {
|
||||
+ status: 400,
|
||||
+ headers: { "content-type": "application/json" },
|
||||
+ },
|
||||
+ );
|
||||
+ }
|
||||
+ return createSseResponse([
|
||||
+ {
|
||||
+ id: "chatcmpl-or",
|
||||
+ object: "chat.completion.chunk",
|
||||
+ created: 0,
|
||||
+ model: model.id,
|
||||
+ choices: [{ index: 0, delta: { content: "Hello" } }],
|
||||
+ },
|
||||
+ {
|
||||
+ id: "chatcmpl-or",
|
||||
+ object: "chat.completion.chunk",
|
||||
+ created: 0,
|
||||
+ model: model.id,
|
||||
+ choices: [{ index: 0, delta: {}, finish_reason: "stop" }],
|
||||
+ },
|
||||
+ "[DONE]",
|
||||
+ ]);
|
||||
+ },
|
||||
+ { preconnect: originalFetch.preconnect },
|
||||
+ );
|
||||
+
|
||||
+ const result = await streamOpenAICompletions(model, testContext, { apiKey: "test-key" }).result();
|
||||
+ expect(result.stopReason).toBe("stop");
|
||||
+ expect(result.content).toContainEqual({ type: "text", text: "Hello" });
|
||||
+ expect(strictFlags).toEqual([[true], [false]]);
|
||||
+ });
|
||||
+
|
||||
|
||||
it("sends strict=true for openai-responses tool schemas on OpenAI", async () => {
|
||||
const model = getBundledModel("openai", "gpt-5-mini") as Model<"openai-responses">;
|
||||
@@ -1,233 +0,0 @@
|
||||
Subject: [PATCH] fix(openai-completions): require `reasoning_content` for OpenRouter reasoning models
|
||||
|
||||
DeepSeek V4 Pro (and similar reasoning models reached via OpenRouter) reject
|
||||
multi-turn requests in thinking mode with:
|
||||
|
||||
400 The `reasoning_content` in the thinking mode must be passed back to
|
||||
the API.
|
||||
|
||||
omp's existing kimi placeholder injection (`requiresReasoningContentForToolCalls`)
|
||||
covered this requirement only for `thinkingFormat === "openai"`. OpenRouter
|
||||
sets `thinkingFormat === "openrouter"`, so the gate never fired even though
|
||||
the underlying providers behind OpenRouter (DeepSeek, Kimi, etc.) all enforce
|
||||
the same invariant.
|
||||
|
||||
This patch:
|
||||
|
||||
1. Extends `requiresReasoningContentForToolCalls` detection: any
|
||||
reasoning-capable model fronted by OpenRouter now sets the flag.
|
||||
2. Extends the placeholder gate in `convertMessages` to accept
|
||||
`thinkingFormat === "openrouter"` alongside `"openai"`.
|
||||
|
||||
Cross-provider continuations are the dominant trigger: a conversation warmed
|
||||
up by Anthropic Claude (whose reasoning is redacted/encrypted on the wire)
|
||||
followed by a switch to DeepSeek V4 Pro via OpenRouter. omp cannot
|
||||
synthesize plaintext `reasoning_content` from Anthropic's encrypted blocks,
|
||||
so the placeholder satisfies DeepSeek's validator without fabricating a
|
||||
reasoning trace. Real captured reasoning, when present, short-circuits the
|
||||
placeholder via `hasReasoningField` and survives intact.
|
||||
|
||||
Side benefit: also closes a latent gap where Kimi-via-OpenRouter
|
||||
(`thinkingFormat === "openrouter"`) had the compat flag set but the
|
||||
placeholder gate silently rejected it.
|
||||
|
||||
Regression tests cover:
|
||||
- compat flag detection on OpenRouter reasoning models
|
||||
- opt-out for non-reasoning OpenRouter models
|
||||
- cross-provider redacted-thinking placeholder
|
||||
- Kimi-via-OpenRouter placeholder firing
|
||||
- real reasoning preserved over the placeholder
|
||||
|
||||
Applies cleanly on top of patch 0001.
|
||||
|
||||
---
|
||||
diff --git a/packages/ai/src/providers/openai-completions-compat.ts b/packages/ai/src/providers/openai-completions-compat.ts
|
||||
--- a/packages/ai/src/providers/openai-completions-compat.ts
|
||||
+++ b/packages/ai/src/providers/openai-completions-compat.ts
|
||||
@@ -105,7 +105,14 @@
|
||||
? "qwen"
|
||||
: "openai",
|
||||
reasoningContentField: "reasoning_content",
|
||||
- requiresReasoningContentForToolCalls: isKimiModel,
|
||||
+ // Backends that 400 follow-up requests when prior assistant tool-call turns lack `reasoning_content`:
|
||||
+ // - Kimi: documented invariant on its native API and via OpenCode-Go.
|
||||
+ // - Any reasoning-capable model reached through OpenRouter: DeepSeek V4 Pro and similar enforce
|
||||
+ // this server-side whenever the request is in thinking mode. We can't translate Anthropic's
|
||||
+ // redacted/encrypted reasoning into DeepSeek's plaintext form, so cross-provider continuations
|
||||
+ // rely on a placeholder — see `convertMessages` for the placeholder injection.
|
||||
+ requiresReasoningContentForToolCalls:
|
||||
+ isKimiModel || ((provider === "openrouter" || baseUrl.includes("openrouter.ai")) && Boolean(model.reasoning)),
|
||||
requiresAssistantContentForToolCalls: isKimiModel,
|
||||
openRouterRouting: undefined,
|
||||
vercelGatewayRouting: undefined,
|
||||
diff --git a/packages/ai/src/providers/openai-completions.ts b/packages/ai/src/providers/openai-completions.ts
|
||||
--- a/packages/ai/src/providers/openai-completions.ts
|
||||
+++ b/packages/ai/src/providers/openai-completions.ts
|
||||
@@ -1059,12 +1059,21 @@
|
||||
(assistantMsg as any).reasoning_content !== undefined ||
|
||||
(assistantMsg as any).reasoning !== undefined ||
|
||||
(assistantMsg as any).reasoning_text !== undefined;
|
||||
- if (
|
||||
- toolCalls.length > 0 &&
|
||||
+ // Inject a `reasoning_content` placeholder on assistant tool-call turns when the backend
|
||||
+ // rejects history without it. The compat flag captures the rule:
|
||||
+ // - Kimi (native or via OpenCode-Go): chat completion endpoint demands the field.
|
||||
+ // - Reasoning models reached through OpenRouter (e.g. DeepSeek V4 Pro): the underlying
|
||||
+ // provider's thinking-mode validator demands it on every prior assistant turn. omp
|
||||
+ // cannot synthesize real reasoning when the conversation was warmed up by another
|
||||
+ // provider whose reasoning is redacted/encrypted (Anthropic) or simply absent, so we
|
||||
+ // emit a placeholder. Real captured reasoning, when present, is preserved earlier via
|
||||
+ // the `thinkingSignature` echo path and short-circuits via `hasReasoningField`.
|
||||
+ // `thinkingFormat` is gated to formats that consume the field (openai/openrouter chat
|
||||
+ // completions); formats with their own conventions (zai, qwen) are excluded.
|
||||
+ const stubsReasoningContent =
|
||||
compat.requiresReasoningContentForToolCalls &&
|
||||
- compat.thinkingFormat === "openai" &&
|
||||
- !hasReasoningField
|
||||
- ) {
|
||||
+ (compat.thinkingFormat === "openai" || compat.thinkingFormat === "openrouter");
|
||||
+ if (toolCalls.length > 0 && stubsReasoningContent && !hasReasoningField) {
|
||||
const reasoningField = compat.reasoningContentField ?? "reasoning_content";
|
||||
(assistantMsg as any)[reasoningField] = ".";
|
||||
}
|
||||
diff --git a/packages/ai/test/openai-completions-compat.test.ts b/packages/ai/test/openai-completions-compat.test.ts
|
||||
--- a/packages/ai/test/openai-completions-compat.test.ts
|
||||
+++ b/packages/ai/test/openai-completions-compat.test.ts
|
||||
@@ -367,4 +367,137 @@
|
||||
const compat = detectCompat(model);
|
||||
expect(compat.requiresReasoningContentForToolCalls).toBe(true);
|
||||
});
|
||||
+
|
||||
+ it("requires reasoning_content for tool calls on reasoning-capable models via OpenRouter", () => {
|
||||
+ const model: Model<"openai-completions"> = {
|
||||
+ ...(getBundledModel("openrouter", "deepseek/deepseek-v3.2") as Model<"openai-completions">),
|
||||
+ reasoning: true,
|
||||
+ };
|
||||
+ const compat = detectCompat(model);
|
||||
+ expect(compat.thinkingFormat).toBe("openrouter");
|
||||
+ expect(compat.requiresReasoningContentForToolCalls).toBe(true);
|
||||
+ });
|
||||
+
|
||||
+ it("does not require reasoning_content for non-reasoning OpenRouter models", () => {
|
||||
+ const model: Model<"openai-completions"> = {
|
||||
+ ...(getBundledModel("openrouter", "deepseek/deepseek-v3.2") as Model<"openai-completions">),
|
||||
+ reasoning: false,
|
||||
+ };
|
||||
+ const compat = detectCompat(model);
|
||||
+ expect(compat.requiresReasoningContentForToolCalls).toBe(false);
|
||||
+ });
|
||||
+
|
||||
+ it("injects reasoning_content placeholder for OpenRouter reasoning models lacking captured reasoning", () => {
|
||||
+ // Reproduces the failing path from real usage: a conversation generated under Anthropic Claude (whose
|
||||
+ // reasoning is redacted/encrypted) is continued with deepseek/deepseek-v4-pro via OpenRouter. The
|
||||
+ // prior assistant turns persist as ThinkingContent blocks with empty `thinking` text plus an opaque
|
||||
+ // Anthropic signature cookie. omp cannot translate that into DeepSeek's plain-text `reasoning_content`,
|
||||
+ // so the empty thinking block is filtered out and the placeholder fires — satisfying DeepSeek's
|
||||
+ // thinking-mode validator without fabricating a reasoning trace.
|
||||
+ const model: Model<"openai-completions"> = {
|
||||
+ ...(getBundledModel("openrouter", "deepseek/deepseek-v3.2") as Model<"openai-completions">),
|
||||
+ reasoning: true,
|
||||
+ };
|
||||
+ const compat = detectCompat(model);
|
||||
+ const toolCallMessage: AssistantMessage = {
|
||||
+ role: "assistant",
|
||||
+ content: [
|
||||
+ // Anthropic-style redacted thinking block: empty text plus opaque signature.
|
||||
+ // `thinking.trim().length === 0` filters this out before the signature echo can fire.
|
||||
+ { type: "thinking", thinking: "", thinkingSignature: "Ep4CClkIDRgCKkDOpaqueAnthropicCookie" },
|
||||
+ { type: "toolCall", id: "call_anth_to_ds", name: "web_search", arguments: { query: "hi" } },
|
||||
+ ],
|
||||
+ api: model.api,
|
||||
+ provider: model.provider,
|
||||
+ model: model.id,
|
||||
+ usage: {
|
||||
+ input: 0,
|
||||
+ output: 0,
|
||||
+ cacheRead: 0,
|
||||
+ cacheWrite: 0,
|
||||
+ totalTokens: 0,
|
||||
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
||||
+ },
|
||||
+ stopReason: "toolUse",
|
||||
+ timestamp: Date.now(),
|
||||
+ };
|
||||
+ const messages = convertMessages(model, { messages: [toolCallMessage] }, compat);
|
||||
+ const assistant = messages.find(m => m.role === "assistant");
|
||||
+ expect(assistant).toBeDefined();
|
||||
+ expect(Reflect.get(assistant as object, "reasoning_content")).toBe(".");
|
||||
+ });
|
||||
+
|
||||
+ it("injects reasoning_content placeholder for kimi-k2-5 via OpenRouter (closes the kimi-via-openrouter gap)", () => {
|
||||
+ // Before this fix, `requiresReasoningContentForToolCalls` was true for Kimi via OpenRouter but the
|
||||
+ // stub gate only fired when `thinkingFormat === "openai"`. OpenRouter sets thinkingFormat="openrouter",
|
||||
+ // so the stub silently never fired and Kimi-via-OpenRouter conversations 400'd the same way.
|
||||
+ const model: Model<"openai-completions"> = {
|
||||
+ ...getBundledModel("openai", "gpt-4o-mini"),
|
||||
+ api: "openai-completions",
|
||||
+ provider: "openrouter",
|
||||
+ baseUrl: "https://openrouter.ai/api/v1",
|
||||
+ id: "moonshotai/kimi-k2-5",
|
||||
+ reasoning: true,
|
||||
+ };
|
||||
+ const compat = detectCompat(model);
|
||||
+ const toolCallMessage: AssistantMessage = {
|
||||
+ role: "assistant",
|
||||
+ content: [
|
||||
+ { type: "toolCall", id: "call_kimi_or", name: "web_search", arguments: { query: "hi" } },
|
||||
+ ],
|
||||
+ api: model.api,
|
||||
+ provider: model.provider,
|
||||
+ model: model.id,
|
||||
+ usage: {
|
||||
+ input: 0,
|
||||
+ output: 0,
|
||||
+ cacheRead: 0,
|
||||
+ cacheWrite: 0,
|
||||
+ totalTokens: 0,
|
||||
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
||||
+ },
|
||||
+ stopReason: "toolUse",
|
||||
+ timestamp: Date.now(),
|
||||
+ };
|
||||
+ const messages = convertMessages(model, { messages: [toolCallMessage] }, compat);
|
||||
+ const assistant = messages.find(m => m.role === "assistant");
|
||||
+ expect(assistant).toBeDefined();
|
||||
+ expect(Reflect.get(assistant as object, "reasoning_content")).toBe(".");
|
||||
+ });
|
||||
+
|
||||
+ it("preserves real captured reasoning over the placeholder when the assistant has non-empty thinking", () => {
|
||||
+ // Sanity check: the placeholder must not overwrite real reasoning. When the prior assistant turn was
|
||||
+ // generated by the same provider and surfaces plaintext reasoning, the existing thinkingSignature
|
||||
+ // echo path sets `reasoning_content` first, and `hasReasoningField` short-circuits the stub.
|
||||
+ const model: Model<"openai-completions"> = {
|
||||
+ ...(getBundledModel("openrouter", "deepseek/deepseek-v3.2") as Model<"openai-completions">),
|
||||
+ reasoning: true,
|
||||
+ };
|
||||
+ const compat = detectCompat(model);
|
||||
+ const toolCallMessage: AssistantMessage = {
|
||||
+ role: "assistant",
|
||||
+ content: [
|
||||
+ { type: "thinking", thinking: "Step 1: read the file. Step 2: search.", thinkingSignature: "reasoning_content" },
|
||||
+ { type: "toolCall", id: "call_real", name: "web_search", arguments: { query: "hi" } },
|
||||
+ ],
|
||||
+ api: model.api,
|
||||
+ provider: model.provider,
|
||||
+ model: model.id,
|
||||
+ usage: {
|
||||
+ input: 0,
|
||||
+ output: 0,
|
||||
+ cacheRead: 0,
|
||||
+ cacheWrite: 0,
|
||||
+ totalTokens: 0,
|
||||
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
||||
+ },
|
||||
+ stopReason: "toolUse",
|
||||
+ timestamp: Date.now(),
|
||||
+ };
|
||||
+ const messages = convertMessages(model, { messages: [toolCallMessage] }, compat);
|
||||
+ const assistant = messages.find(m => m.role === "assistant");
|
||||
+ expect(assistant).toBeDefined();
|
||||
+ expect(Reflect.get(assistant as object, "reasoning_content")).toBe("Step 1: read the file. Step 2: search.");
|
||||
+ });
|
||||
+
|
||||
});
|
||||
34
patches/zfs/0001-remove-dbuf_evict_one-call.patch
Normal file
34
patches/zfs/0001-remove-dbuf_evict_one-call.patch
Normal file
@@ -0,0 +1,34 @@
|
||||
--- a/module/zfs/dbuf.c 2026-04-24 14:20:12.565390796 -0400
|
||||
+++ b/module/zfs/dbuf.c 2026-04-24 14:20:40.711198653 -0400
|
||||
@@ -864,23 +864,16 @@
|
||||
dbuf_evict_notify(uint64_t size)
|
||||
{
|
||||
/*
|
||||
- * We check if we should evict without holding the dbuf_evict_lock,
|
||||
- * because it's OK to occasionally make the wrong decision here,
|
||||
- * and grabbing the lock results in massive lock contention.
|
||||
+ * Wake the dedicated eviction thread when the cache
|
||||
+ * exceeds target. Inline eviction from write-completion
|
||||
+ * context is intentionally avoided: it adds a second
|
||||
+ * multilist sublist lock to every write, and when
|
||||
+ * kmem_cache_free is slow (__free_frozen_pages zone lock
|
||||
+ * contention on 6.14+), the cascade stalls txg_sync.
|
||||
+ * See openzfs#18426.
|
||||
*/
|
||||
- if (size > dbuf_cache_target_bytes()) {
|
||||
- /*
|
||||
- * Avoid calling dbuf_evict_one() from memory reclaim context
|
||||
- * (e.g. Linux kswapd, FreeBSD pagedaemon) to prevent deadlocks.
|
||||
- * Memory reclaim threads can get stuck waiting for the dbuf
|
||||
- * hash lock.
|
||||
- */
|
||||
- if (size > dbuf_cache_hiwater_bytes() &&
|
||||
- !current_is_reclaim_thread()) {
|
||||
- dbuf_evict_one();
|
||||
- }
|
||||
+ if (size > dbuf_cache_target_bytes())
|
||||
cv_signal(&dbuf_evict_cv);
|
||||
- }
|
||||
}
|
||||
|
||||
/*
|
||||
Reference in New Issue
Block a user