Compare commits
530 Commits
skills
..
8c42ca14fc
| Author | SHA1 | Date | |
|---|---|---|---|
| 8c42ca14fc | |||
| cc4471149c | |||
|
ddad7166ad
|
|||
|
77113fb4ef
|
|||
|
ac3eb40195
|
|||
|
b6be2229cf
|
|||
|
acf69f7ed7
|
|||
| 8e4ecd454c | |||
|
25d8395948
|
|||
|
7b0d4ca41f
|
|||
|
b7ca5165c6
|
|||
|
36e0a0013c
|
|||
|
fa3f27532e
|
|||
|
8e2a5ce31e
|
|||
|
e91ea86873
|
|||
|
d494f8825f
|
|||
|
5e8194d271
|
|||
|
b40ae70084
|
|||
|
25593037f6
|
|||
|
7b679a2966
|
|||
|
d570c59fb0
|
|||
|
f96fd744e7
|
|||
|
dcc6bcd0e7
|
|||
|
6499b2fe83
|
|||
|
b48716d7f8
|
|||
|
cae279c9e0
|
|||
|
8b7306341c
|
|||
|
fb4a46c5b8
|
|||
|
af7ea9b5bc
|
|||
|
68b51bf10e
|
|||
|
721ca1bc10
|
|||
|
eb102e1374
|
|||
|
bc2174286e
|
|||
|
1b4ab894d4
|
|||
|
1c983fb144
|
|||
|
09fb6634f0
|
|||
|
46ddfdc464
|
|||
|
df6c3c50db
|
|||
|
8c5bed3e34
|
|||
|
d45375a454
|
|||
|
ed8327e9d6
|
|||
|
bc1800db4f
|
|||
|
dd8da58105
|
|||
|
6a0df70777
|
|||
|
5e550a67ce
|
|||
|
b781dd8dc6
|
|||
|
43fbe448cb
|
|||
|
9efd6a2690
|
|||
|
a3f278544a
|
|||
|
e48926f458
|
|||
|
4e616fe7c3
|
|||
|
863b28f01e
|
|||
|
bf97f2261d
|
|||
|
baa44ec5cb
|
|||
|
29af20f316
|
|||
|
960a199cd2
|
|||
|
3a18ffdaf3
|
|||
|
7aa00d52de
|
|||
|
ac58ddc202
|
|||
|
38259642cd
|
|||
|
90e105a171
|
|||
|
a5ece505b7
|
|||
|
fb8633dc75
|
|||
|
a7ebc15b89
|
|||
|
a7a9b6b1cf
|
|||
|
e1c2f0aa42
|
|||
|
6e9b394f73
|
|||
|
747ca0d0fc
|
|||
|
ba665528ed
|
|||
|
1440e23748
|
|||
|
8ff9d84a85
|
|||
|
dc8e831f27
|
|||
|
985ae11fcf
|
|||
|
b758b17dbb
|
|||
|
aef26013cb
|
|||
|
b1fc199a5f
|
|||
|
7e801b80d0
|
|||
|
7cd7abe469
|
|||
|
6a5561edba
|
|||
|
d8a92f4e62
|
|||
|
6330d7dd95
|
|||
|
c63eb0a9f9
|
|||
|
d927a9b99f
|
|||
|
766684615b
|
|||
|
5be12e90dc
|
|||
|
7325ad7b32
|
|||
|
2e224948d4
|
|||
|
fa424bde34
|
|||
|
42c88fa2a3
|
|||
|
84c6f88cf2
|
|||
|
f401c637cc
|
|||
|
3239c5d990
|
|||
|
1dff08893a
|
|||
|
f65ec9e9fe
|
|||
|
3ce5ab4fe7
|
|||
| fd21431c2f | |||
| 61a698f9eb | |||
|
518a39c143
|
|||
|
160ee5d5ae
|
|||
|
e4819ff9db
|
|||
|
ecb3cdfcc2
|
|||
|
364cf29296
|
|||
|
b2fa8ebb71
|
|||
| 48031d592f | |||
|
4c7a0a7a77
|
|||
|
8f960fdbbf
|
|||
|
feefe45ed2
|
|||
| 9958eeee8f | |||
|
aa31db7e07
|
|||
|
8c6dde7d86
|
|||
|
738e29059b
|
|||
|
2eb81c4a8b
|
|||
|
88998d1019
|
|||
|
a1fc099c24
|
|||
|
2fe365bef8
|
|||
|
efb1b7b96b
|
|||
|
d915f9e3c1
|
|||
|
11ebf3c155
|
|||
|
abf5d425fd
|
|||
|
1e3d52482a
|
|||
|
0fb72f8226
|
|||
|
0701c370b4
|
|||
|
0bdaa9441f
|
|||
|
4ba1bd8a24
|
|||
|
b484242e4c
|
|||
|
a756394e30
|
|||
|
0faf7b850d
|
|||
|
eeb9f7083b
|
|||
|
b6a5b340f1
|
|||
|
209257c7b1
|
|||
|
4e88cebe28
|
|||
|
738b600fa6
|
|||
|
f67538e5ab
|
|||
|
18bb3d3440
|
|||
|
04cd3c890b
|
|||
|
ef8f5865e2
|
|||
|
493e9bb2a5
|
|||
|
3eff135349
|
|||
|
7ac753d824
|
|||
|
9add71ff13
|
|||
|
7154c3a652
|
|||
|
36ac924d77
|
|||
|
5e4d3ff011
|
|||
|
fd287b09b0
|
|||
|
07c1f70df3
|
|||
|
8c398b6360
|
|||
|
e43c2e477a
|
|||
|
6078072915
|
|||
|
1902e2d040
|
|||
|
702e6f2f63
|
|||
|
01938a0f28
|
|||
|
5d017fbb48
|
|||
|
a3ed9476ae
|
|||
|
a22faad992
|
|||
|
06fe1f9471
|
|||
|
e2ff2c03f8
|
|||
|
7ca9a19d3b
|
|||
|
f5b69d6b4d
|
|||
|
4f244618ca
|
|||
|
b7a20a000a
|
|||
|
0094be475f
|
|||
|
3e508c9337
|
|||
|
edd3c08247
|
|||
|
bf6b2f718c
|
|||
|
984a073730
|
|||
|
aa4babff56
|
|||
|
7f620d469b
|
|||
|
33782c59a8
|
|||
|
5669830510
|
|||
|
99c6cff068
|
|||
|
9b395a304d
|
|||
|
01912bcef3
|
|||
|
e0b85fc936
|
|||
|
73f6e07e47
|
|||
|
534b9923ae
|
|||
|
c66faa22dc
|
|||
|
cf666eb2c6
|
|||
|
76861508c9
|
|||
|
beebb39050
|
|||
|
3d7ba424f1
|
|||
|
84eb82b355
|
|||
|
1fbdcd66d1
|
|||
|
5b65496684
|
|||
|
ca808b4c08
|
|||
|
84c1753ed5
|
|||
|
c8d9f89d59
|
|||
|
e3531b4dcf
|
|||
|
b939868d28
|
|||
|
7630b3e75c
|
|||
| 3292f8e0a5 | |||
|
cf1c06e632
|
|||
|
49f2932b30
|
|||
|
5fd786dd3d
|
|||
|
f5967c7771
|
|||
|
eee0e86131
|
|||
|
51dfd2a655
|
|||
|
d9cf0c4b08
|
|||
|
b4c65f7a19
|
|||
|
1c0e836a92
|
|||
|
2da196c091
|
|||
|
69648afe27
|
|||
|
454f5c03f3
|
|||
|
406642723e
|
|||
|
2469b713c7
|
|||
|
b6ad7a575d
|
|||
|
f3b410d146
|
|||
|
095d0f3d8a
|
|||
|
5f445e046f
|
|||
|
96ab2bdc1b
|
|||
|
cb175e3b51
|
|||
|
7965b970d9
|
|||
|
0a21f10b04
|
|||
|
49aa9fad41
|
|||
|
8f7d3bd13c
|
|||
|
f7fb249d43
|
|||
|
d9498ffb21
|
|||
|
0177fa6906
|
|||
|
c3f6cb8f46
|
|||
|
7facdce6b6
|
|||
|
c11eb352fe
|
|||
|
0e427dc4ba
|
|||
|
f1914f6bd4
|
|||
|
dba6304f51
|
|||
|
e40a8bba72
|
|||
|
c057249e52
|
|||
|
d906713d7d
|
|||
| ff3419a714 | |||
|
a5899da4fb
|
|||
|
dedcef8ac5
|
|||
|
d658f1d2fe
|
|||
|
6b4a45874f
|
|||
|
7839e1dbd9
|
|||
|
78c3932f36
|
|||
|
11334149b0
|
|||
|
4caa035528
|
|||
|
f30e81af08
|
|||
|
4c75655f58
|
|||
|
f865892c28
|
|||
|
ebeb9c9b7d
|
|||
|
ab2b927fcb
|
|||
|
7e5ff2ba1f
|
|||
|
ed59051f3d
|
|||
| e98bf56a2b | |||
| fb510b1a4f | |||
|
6c17462040
|
|||
|
1536cf384c
|
|||
|
d6842d7e29
|
|||
|
fbc0acda2a
|
|||
|
0327d041b6
|
|||
|
6a01fd4fbd
|
|||
| d822180205 | |||
|
89d0fdce26
|
|||
|
b3ecdce979
|
|||
|
3873821a31
|
|||
|
9c2801b643
|
|||
|
d78820dcd4
|
|||
|
d43c4232a2
|
|||
|
f41c85b703
|
|||
|
9e056bdcf0
|
|||
|
d6022b9f98
|
|||
|
6fc1abf94a
|
|||
|
92ea0f624e
|
|||
|
c3fd8fbc1c
|
|||
|
7fd3f7761c
|
|||
|
05e19098b2
|
|||
|
60067ae757
|
|||
|
c72003b0b6
|
|||
|
7c9d500116
|
|||
|
6b2c87b562
|
|||
|
b2dbdfb4b1
|
|||
|
063e198f96
|
|||
|
73cbe16ec1
|
|||
|
bdea854a9f
|
|||
|
9b4c800597
|
|||
|
eb4d1c02f4
|
|||
|
c428990900
|
|||
|
03b9cc70b9
|
|||
|
3fa0eb832c
|
|||
|
83f66e1061
|
|||
|
741b9c364c
|
|||
|
b6f6f456db
|
|||
|
00a6cf74d7
|
|||
|
d35ca352ca
|
|||
| 57dc1cb252 | |||
|
101a9cdd6e
|
|||
|
c5f52e1efb
|
|||
|
470149b606
|
|||
|
02062c5a50
|
|||
|
e6e99b6926
|
|||
|
15a293204f
|
|||
|
ecf3780aed
|
|||
|
e798747135
|
|||
|
60493728a0
|
|||
|
25d6370b20
|
|||
|
d67f845af5
|
|||
|
920a14cabe
|
|||
|
58bdd2e584
|
|||
|
ce6f53ad05
|
|||
|
96f8007d53
|
|||
|
32a55652fe
|
|||
|
2b92e6c98b
|
|||
|
cfa654bcd8
|
|||
|
d0f5ae39e2
|
|||
|
2bb8cf5f73
|
|||
|
fbac446859
|
|||
|
f91cf2e346
|
|||
|
b6b33ab7e3
|
|||
|
c1902a69d1
|
|||
|
812a8e101c
|
|||
|
655ee2a599
|
|||
|
128a8f9a9c
|
|||
|
b1be9443e7
|
|||
|
7b12c69ebf
|
|||
|
69ad584137
|
|||
|
313058e70a
|
|||
|
ea96d9ba3d
|
|||
|
7884adc7c1
|
|||
|
948466d771
|
|||
|
3894c98b5b
|
|||
|
5e9c31595e
|
|||
|
39d9b25e47
|
|||
|
b86f76ddb9
|
|||
|
7f267a10a1
|
|||
|
cdafdff281
|
|||
|
60ad83d6d9
|
|||
|
44c03ccf4f
|
|||
|
af933bbb29
|
|||
|
1f127ee990
|
|||
|
88a9a7709f
|
|||
| e8d92d1b01 | |||
| ddbfd03e75 | |||
|
d1c7f09015
|
|||
|
d2f8f995f0
|
|||
|
5ef9a397ca
|
|||
|
325ab1f45e
|
|||
|
4cfaa2dc77
|
|||
|
6abe2c5536
|
|||
|
03cfd59962
|
|||
|
4d7d5e5e53
|
|||
|
3779b940ae
|
|||
|
d2e541c5c0
|
|||
|
621c90427c
|
|||
|
486001ee85
|
|||
|
c7a2ec084f
|
|||
|
d4e0d48198
|
|||
|
07f23bab5e
|
|||
|
b11797ea1c
|
|||
|
70c2d411ae
|
|||
|
f82c9aff40
|
|||
|
a935add2a7
|
|||
|
8a37a88ffd
|
|||
|
8f66cac680
|
|||
|
0a40ddd2e4
|
|||
|
d5e0728532
|
|||
|
25c0885dcc
|
|||
|
f56ed7d005
|
|||
|
d79e4b9dff
|
|||
|
cdd829199f
|
|||
|
e3c644b8ca
|
|||
|
5cb8070da1
|
|||
|
66801b5d07
|
|||
|
f2de196e22
|
|||
|
2eba530895
|
|||
| 3baa3102a3 | |||
| 2d4fad596c | |||
| 7259e59d2a | |||
| cec04c4597 | |||
| a7f5677195 | |||
| 6075f0a190 | |||
| 15310a9e2c | |||
| f7df54f2f7 | |||
| 212d4bace4 | |||
| f4b3267c89 | |||
| 9eeeb11871 | |||
| b8db3f689d | |||
| 3b21ce2aa5 | |||
| 9bf4fcd943 | |||
| c1f5cfbbda | |||
| 46517a4e15 | |||
| efbe76e1fc | |||
| 245c567d30 | |||
| cbb3d2c34a | |||
| bddec85fa5 | |||
| 96acbc6bf0 | |||
| 0735a31190 | |||
| 986c64ff13 | |||
| 831426d418 | |||
| b99e3fc030 | |||
| 012734f70a | |||
| f591a9635e | |||
| 7c099bf589 | |||
| 32d3cee907 | |||
| 86539c4bb8 | |||
| 14549afd52 | |||
| 667c843fc0 | |||
| 680a52982c | |||
| 52efb1a775 | |||
| c88931d318 | |||
| 2183ed62d1 | |||
| cc8bd040b9 | |||
| a2a464151f | |||
| c9a3f247e7 | |||
| d167502b7b | |||
| 0d9927bb99 | |||
| c9858ce615 | |||
| cccaa1dbe7 | |||
| acd951e981 | |||
| 10d80d58fd | |||
| f196c375d6 | |||
| cc62c89b05 | |||
| 3266cdeb08 | |||
| 6605c62015 | |||
| 704fdbd145 | |||
| 93e76a65a1 | |||
| b3ca7ebddb | |||
| 091fc0b7b7 | |||
| 874f5ba08e | |||
| 5fdfe94b88 | |||
| c02b168749 | |||
| 6ababd919d | |||
| 86b2b2d772 | |||
| 2aa2c3ccee | |||
| 70645a8431 | |||
| ca4b2f2637 | |||
| 7fce8f9b23 | |||
| e5b3b332f6 | |||
| 3e59762443 | |||
| 2ea8a48f28 | |||
| 3c07471620 | |||
| 23e2c1144f | |||
| 313f5e2dda | |||
| 26c35e55d8 | |||
| 878adc0eb7 | |||
| d353767b2c | |||
| 33baeaa62d | |||
| 591b7a5bf1 | |||
| 0bc993532b | |||
| 09379e7231 | |||
| 1a45ce9dc1 | |||
| 95df054dfb | |||
| 5b49553c6d | |||
| 6508940d11 | |||
| 71d89eaaba | |||
| 9619b7908f | |||
| 304129d793 | |||
| 5df435c21a | |||
| 2719c7320a | |||
| a84bae189c | |||
| d82c7c2535 | |||
| 2bc832ed95 | |||
| b5a0f0635b | |||
| 7426aa4bcb | |||
| ba9649382e | |||
| 9c64e97d8b | |||
| 4b1cd3cf44 | |||
| 4a0f002503 | |||
| c4f8c6e102 | |||
| 421308423f | |||
| 0550de2093 | |||
| dddf72e1da | |||
| e23820adf2 | |||
| fea4411aa6 | |||
| b814a38c59 | |||
| 1a3476e4fb | |||
| ecd4d6587c | |||
| 0938119e99 | |||
| 9f15f01871 | |||
| f09cbd2b32 | |||
| 77c1a06277 | |||
| 600f5d1484 | |||
| 7f71317acd | |||
| 865ef5827b | |||
| e5d5bf6c53 | |||
| 7b08d1ef96 | |||
| 9d363b38c7 | |||
| 2f3586cbbf | |||
| 843abe0621 | |||
| 474c5bc76f | |||
| b49a27f886 | |||
| 6f77b3f46e | |||
| a835012673 | |||
| 3f1e8003f8 | |||
| 8475707e75 | |||
| 8a240b1c3f | |||
| 59a3e3012b | |||
| c13142f971 | |||
| a468ee1154 | |||
| 1b504e211a | |||
| 29536f6291 | |||
| 4ef483126d | |||
| 8d2961f3ee | |||
| f1146bb2b9 | |||
| 2daa014c99 | |||
| ebe642f44a | |||
| 25ad254e84 | |||
| 947a7871c2 | |||
| 6421a677eb | |||
| 950893f4a2 | |||
| a10948614d | |||
| 39fc863e22 | |||
| df8b326d89 | |||
| 591f204b67 | |||
| 316ebd6d25 | |||
| 4e707ae08e | |||
| 1ef554c759 | |||
| 367e7d90fd | |||
| 6e7a89763c | |||
| 9dd3836802 | |||
| f822546971 | |||
| 4bf338f91a | |||
| 16577ddc5e | |||
| 384ae73c80 | |||
| d4c932b8ac | |||
| 743e42d4f8 | |||
| 6be2651106 | |||
| 2a2d20a25c | |||
| 882942385b | |||
| 0aa908c8d3 | |||
| 4c179c9269 | |||
| a4fe91ffda | |||
| dc500207ef | |||
| c1e3c3699b | |||
| 52e9f5fc70 | |||
| c85cddb5b4 | |||
| 477b53124d | |||
| 650dbd92e0 | |||
| 88288a98b6 | |||
| 377ab91af7 | |||
| acfc7685f4 | |||
| 5636010e1e |
@@ -1,3 +1,84 @@
|
|||||||
|
## v0.6.0 (2026-06-05)
|
||||||
|
|
||||||
|
### Feat
|
||||||
|
|
||||||
|
- added skill hint prompt injection and configuration
|
||||||
|
- Fallthrough on missing secrets during mcp.json merging
|
||||||
|
- validate visible_skills field at config load time
|
||||||
|
- implemented reflexion (sorta) in sisyphus for significant code changes to delegate to the code-reviewer agent
|
||||||
|
- improved explore agent
|
||||||
|
- removed conditional fallback of LLM_*_RAW_JSON from built-ins
|
||||||
|
- updated enabled_skills handling to support both list and comma-separated strings
|
||||||
|
- added new REPL set commands for toggling skills and changing what skills are enabled
|
||||||
|
- upgraded to the latest version of mcp-remote
|
||||||
|
- fs_grep now works with both files and directories
|
||||||
|
- improved code reviewer agents with skills
|
||||||
|
- added round trip validation for vault providers to ensure permissions and authentication
|
||||||
|
- created new first-time run wizard for secrets provider
|
||||||
|
- vault_password_file or nothing at all is shorthand for just using the local gman provider for secret management
|
||||||
|
- refactored gman usage to be generic and work with various vault providers and use the SupportedProvider enum directly for configurations
|
||||||
|
- created initial parity gman generalization for vault provider
|
||||||
|
- Refactored the sisyhpus agent system to utilize the new skills system to improve performance and reliability
|
||||||
|
- llm graph nodes support skills
|
||||||
|
- updated sisyphus and coder tools
|
||||||
|
- removed potentially confusing tab completions for .skill
|
||||||
|
- .edit skill <name> support from within the REPL
|
||||||
|
- Added skills_dir to the info output of Coyote
|
||||||
|
- Created a few auto built-in skills
|
||||||
|
- Added support for auto_unload skills during chat
|
||||||
|
- cleaned up skill implementation
|
||||||
|
- support multiple skill flags to load multiple skills at CLI startup
|
||||||
|
- Modified --skill CLI to allow users to specify skills to start the REPL or CLI with.
|
||||||
|
- added CLI --skill flag for modifying skills easily
|
||||||
|
- REPL integration with skills
|
||||||
|
- dynamic loading/unloading of skill tools and MCP servers whenever load_skill/unload_skill are invoked
|
||||||
|
- created built-in functions for listing, loading, and unloading skills
|
||||||
|
- implemented the skills policy to track available skills per context
|
||||||
|
- added remote install and install support for skills
|
||||||
|
- created the skill registry
|
||||||
|
- decided to make skills persist to disk like agents and not in-memory like built-in roles
|
||||||
|
- scaffold skill module
|
||||||
|
|
||||||
|
### Fix
|
||||||
|
|
||||||
|
- disable skills for specific built-in roles
|
||||||
|
- redirect stderr into user's /dev/tty for guards
|
||||||
|
- azure doesn't support underscores in key vault
|
||||||
|
- accidental regression on enabled_skills being empty = all
|
||||||
|
- greedy secrets regex caused multiple secrets on one line to fail
|
||||||
|
- add agent context check to skill visibility validation
|
||||||
|
- enforced global visible_skills in llm node validation and improved skill loading error handling across the project
|
||||||
|
- restore agent skill policy on error during effective policy calculation
|
||||||
|
- apply the same validation for skill filenames on list_skills as happens everywhere else
|
||||||
|
- the vault's init_bare should try to load the provisioned secret_provider from the config file without also interpolating any of the rest of the configuration file. It should only fail if the user has not yet created a configuration file; i.e. done a first-time run.
|
||||||
|
- the vault roundtrip test used characters that are unsupported by some major secrets providers
|
||||||
|
- fixed tool filtering logic for skills and user functions in agents
|
||||||
|
- privilege leak when unloading skills and leaving tool scope untouched
|
||||||
|
- When bootstrapping an app config to interpolate secrets, clone the secrets provider configuration as well so config secrets stored in remote vaults can be used properly
|
||||||
|
- forgot to move back up the vault probe value error to be before the delete
|
||||||
|
- don't silently fail on skill role composition extraction in llm nodes
|
||||||
|
- set -euo pipefail for the temp script in execute_command.sh tool
|
||||||
|
- added forgotten skill name validation to has_skill to prevent side-channel attacks
|
||||||
|
- use unique values for the secrets round trip verification
|
||||||
|
- stop interpolating a line if any errors occur
|
||||||
|
- added path validation for skill names
|
||||||
|
- effective_policy unconditionally overwrote skill values for role-like structs
|
||||||
|
- updated execute_command to not mangle heredocs and also added explicit instructions to the coder and sisyphus agents to use fs_write and fs_patch over execute_command when writing files
|
||||||
|
- llm nodes accidentally skipped skill_registry::effective_role because I was passing an inline role instead
|
||||||
|
- updated temperature values for all agents and roles
|
||||||
|
- added back in require_max_tokens for new Claude models
|
||||||
|
- skill support also requires function calling to be enabled
|
||||||
|
- non_tty tests break on some TTY terminals
|
||||||
|
- skill loading on agents
|
||||||
|
- forgot to bootstrap skills on REPL startup
|
||||||
|
- remove now deprecated .skill edit command
|
||||||
|
|
||||||
|
### Refactor
|
||||||
|
|
||||||
|
- removed redundant skill name validation from has_skill function
|
||||||
|
- support both CSV and list formats for enabled_tools
|
||||||
|
- Support both CSV and list formats for enabled_mcp_servers
|
||||||
|
|
||||||
## v0.5.0 (2026-05-27)
|
## v0.5.0 (2026-05-27)
|
||||||
|
|
||||||
### Feat
|
### Feat
|
||||||
|
|||||||
Generated
+92
-98
@@ -278,9 +278,9 @@ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-config"
|
name = "aws-config"
|
||||||
version = "1.8.17"
|
version = "1.8.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "517aa062d8bd9015ee23d6daa5e1c1372328412fdae4e6c4c1be9b69c6ad37a2"
|
checksum = "e33f815b73a3899c03b380d543532e5865f230dce9678d108dc10732a8682275"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-credential-types",
|
"aws-credential-types",
|
||||||
"aws-runtime",
|
"aws-runtime",
|
||||||
@@ -381,10 +381,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-sdk-secretsmanager"
|
name = "aws-sdk-secretsmanager"
|
||||||
version = "1.105.0"
|
version = "1.107.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1c4e56ac810211dc33810c7aa3612eda29a8b1e8c7e2db6e960c8657e3d95e42"
|
checksum = "63da8ec2dca98a68d8bcba971abae5f06e2c9c0017f43097d1ff92cff96adc54"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"arc-swap",
|
||||||
"aws-credential-types",
|
"aws-credential-types",
|
||||||
"aws-runtime",
|
"aws-runtime",
|
||||||
"aws-smithy-async",
|
"aws-smithy-async",
|
||||||
@@ -405,10 +406,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-sdk-sso"
|
name = "aws-sdk-sso"
|
||||||
version = "1.99.0"
|
version = "1.101.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9f4055e6099b2ec264abdc0d9bbfffce306c1601809275c861594779a0b04b45"
|
checksum = "b647baea49ff551960b904f905681e9b4765a6c4ea08631e89dc52d8bd3f5896"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"arc-swap",
|
||||||
"aws-credential-types",
|
"aws-credential-types",
|
||||||
"aws-runtime",
|
"aws-runtime",
|
||||||
"aws-smithy-async",
|
"aws-smithy-async",
|
||||||
@@ -429,10 +431,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-sdk-ssooidc"
|
name = "aws-sdk-ssooidc"
|
||||||
version = "1.101.0"
|
version = "1.103.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "02f009ba0284c5d696425fd7b4dcc5b189f5726f4041b7a5794daecb3a68d598"
|
checksum = "7ae401c65ff288aa7873117fe535cd32b7b1bb0bc43751d28901a1d5f20636b9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"arc-swap",
|
||||||
"aws-credential-types",
|
"aws-credential-types",
|
||||||
"aws-runtime",
|
"aws-runtime",
|
||||||
"aws-smithy-async",
|
"aws-smithy-async",
|
||||||
@@ -453,10 +456,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-sdk-sts"
|
name = "aws-sdk-sts"
|
||||||
version = "1.104.0"
|
version = "1.106.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6aa6622798e19e6a76b690562085dd4771c736cd48343464a53ab4ae2f2c9f84"
|
checksum = "4c80de7bb7d03e9ca8c9fd7b489f20f3948d3f3be91a7953591347d238115408"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"arc-swap",
|
||||||
"aws-credential-types",
|
"aws-credential-types",
|
||||||
"aws-runtime",
|
"aws-runtime",
|
||||||
"aws-smithy-async",
|
"aws-smithy-async",
|
||||||
@@ -478,9 +482,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-sigv4"
|
name = "aws-sigv4"
|
||||||
version = "1.4.4"
|
version = "1.4.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b7083fb918b38474ac65ffbf8a69fc8792d36879f4ac5f1667b43aec61efe9a5"
|
checksum = "bae38512beae0ffee7010fc24e7a8a123c53efdfef42a61e80fda4882418dc71"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-credential-types",
|
"aws-credential-types",
|
||||||
"aws-smithy-http",
|
"aws-smithy-http",
|
||||||
@@ -543,9 +547,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-smithy-http-client"
|
name = "aws-smithy-http-client"
|
||||||
version = "1.1.12"
|
version = "1.1.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a2f165a7feee6f263028b899d0a181987f4fa7179a6411a32a439fba7c5f769"
|
checksum = "5c3ef8931ad1c98aa6a55b4256f847f3116090819844e0dd41ea682cac5dd2d3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-smithy-async",
|
"aws-smithy-async",
|
||||||
"aws-smithy-runtime-api",
|
"aws-smithy-runtime-api",
|
||||||
@@ -556,7 +560,7 @@ dependencies = [
|
|||||||
"http 1.4.1",
|
"http 1.4.1",
|
||||||
"http-body 0.4.6",
|
"http-body 0.4.6",
|
||||||
"hyper 0.14.32",
|
"hyper 0.14.32",
|
||||||
"hyper 1.10.0",
|
"hyper 1.10.1",
|
||||||
"hyper-rustls 0.24.2",
|
"hyper-rustls 0.24.2",
|
||||||
"hyper-rustls 0.27.9",
|
"hyper-rustls 0.27.9",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
@@ -573,9 +577,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-smithy-json"
|
name = "aws-smithy-json"
|
||||||
version = "0.62.6"
|
version = "0.62.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "517089205f18ab4adc5a3e02888cb139bbbbb2e168eac9f396216925d1fbeaf5"
|
checksum = "701a947f4797e52a911e114a898667c746c39feea467bbd1abd7b3721f702ffa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-smithy-runtime-api",
|
"aws-smithy-runtime-api",
|
||||||
"aws-smithy-schema",
|
"aws-smithy-schema",
|
||||||
@@ -629,9 +633,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-smithy-runtime-api"
|
name = "aws-smithy-runtime-api"
|
||||||
version = "1.12.1"
|
version = "1.12.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc117c179ecf39a62a0a3f49f600e9ac26a7ad7dd172177999f83933af776c32"
|
checksum = "9db177daa6ba8afb9ee1aefcf548c907abcf52065e394ee11a92780057fe0e8c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-smithy-async",
|
"aws-smithy-async",
|
||||||
"aws-smithy-runtime-api-macros",
|
"aws-smithy-runtime-api-macros",
|
||||||
@@ -669,9 +673,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-smithy-types"
|
name = "aws-smithy-types"
|
||||||
version = "1.4.8"
|
version = "1.4.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "056b66dbce2f81cc0c1e2b05bb402eb58f8a3530479d650efadd5bbae9a4050b"
|
checksum = "53f93074121a1be41317b9aa607143ae17900631f7f59a99f2b905d519d6783b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64-simd",
|
"base64-simd",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -899,7 +903,7 @@ dependencies = [
|
|||||||
"quote",
|
"quote",
|
||||||
"regex",
|
"regex",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"shlex",
|
"shlex 1.3.0",
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -920,9 +924,9 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.11.1"
|
version = "2.12.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
|
checksum = "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_core",
|
"serde_core",
|
||||||
]
|
]
|
||||||
@@ -1056,14 +1060,14 @@ checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.62"
|
version = "1.2.63"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98"
|
checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"find-msvc-tools",
|
"find-msvc-tools",
|
||||||
"jobserver",
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
"shlex",
|
"shlex 2.0.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1124,9 +1128,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.44"
|
version = "0.4.45"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
|
checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iana-time-zone",
|
"iana-time-zone",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
@@ -1190,7 +1194,7 @@ dependencies = [
|
|||||||
"clap",
|
"clap",
|
||||||
"clap_lex",
|
"clap_lex",
|
||||||
"is_executable",
|
"is_executable",
|
||||||
"shlex",
|
"shlex 1.3.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1241,9 +1245,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cmov"
|
name = "cmov"
|
||||||
version = "0.5.3"
|
version = "0.5.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746"
|
checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorchoice"
|
name = "colorchoice"
|
||||||
@@ -1398,7 +1402,7 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "coyote-ai"
|
name = "coyote-ai"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_colours",
|
"ansi_colours",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
@@ -2333,7 +2337,7 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"chrono",
|
"chrono",
|
||||||
"futures",
|
"futures",
|
||||||
"hyper 1.10.0",
|
"hyper 1.10.1",
|
||||||
"jsonwebtoken",
|
"jsonwebtoken",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"prost",
|
"prost",
|
||||||
@@ -2766,9 +2770,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "1.10.0"
|
version = "1.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eb92f162bf56536459fc83c79b974bb12837acfed43d6bc370a7916d0ae15ecc"
|
checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atomic-waker",
|
"atomic-waker",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -2808,7 +2812,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f"
|
checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"http 1.4.1",
|
"http 1.4.1",
|
||||||
"hyper 1.10.0",
|
"hyper 1.10.1",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"rustls 0.23.40",
|
"rustls 0.23.40",
|
||||||
"rustls-native-certs",
|
"rustls-native-certs",
|
||||||
@@ -2823,7 +2827,7 @@ version = "0.5.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0"
|
checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hyper 1.10.0",
|
"hyper 1.10.1",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"tokio",
|
"tokio",
|
||||||
@@ -2838,7 +2842,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper 1.10.0",
|
"hyper 1.10.1",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"native-tls",
|
"native-tls",
|
||||||
"tokio",
|
"tokio",
|
||||||
@@ -2858,12 +2862,12 @@ dependencies = [
|
|||||||
"futures-util",
|
"futures-util",
|
||||||
"http 1.4.1",
|
"http 1.4.1",
|
||||||
"http-body 1.0.1",
|
"http-body 1.0.1",
|
||||||
"hyper 1.10.0",
|
"hyper 1.10.1",
|
||||||
"ipnet",
|
"ipnet",
|
||||||
"libc",
|
"libc",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"socket2 0.6.3",
|
"socket2 0.6.4",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
"tracing",
|
"tracing",
|
||||||
@@ -3153,9 +3157,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jiff"
|
name = "jiff"
|
||||||
version = "0.2.27"
|
version = "0.2.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "392c70591e8749fe235ddaf513e6f58b26bce3dcc16524cecc8936f75afa161e"
|
checksum = "4603d3033e49e2b0e31229fcab20a5d40089c607d975cd9c80551dc69eed9102"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jiff-static",
|
"jiff-static",
|
||||||
"log",
|
"log",
|
||||||
@@ -3166,9 +3170,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jiff-static"
|
name = "jiff-static"
|
||||||
version = "0.2.27"
|
version = "0.2.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "47b605b0c050d845fc355bb11eb3f9a8deddc218ea60c76e61aa1f2adfb2c96a"
|
checksum = "782d32378dddf207193ac91cefb848ad41abb58195c95168e1291227a0832b47"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -3351,9 +3355,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.30"
|
version = "0.4.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5"
|
checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_core",
|
"serde_core",
|
||||||
]
|
]
|
||||||
@@ -3511,9 +3515,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "1.2.0"
|
version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1"
|
checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
@@ -4412,7 +4416,7 @@ dependencies = [
|
|||||||
"quinn-udp",
|
"quinn-udp",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"rustls 0.23.40",
|
"rustls 0.23.40",
|
||||||
"socket2 0.6.3",
|
"socket2 0.6.4",
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
@@ -4450,7 +4454,7 @@ dependencies = [
|
|||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"libc",
|
"libc",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"socket2 0.6.3",
|
"socket2 0.6.4",
|
||||||
"tracing",
|
"tracing",
|
||||||
"windows-sys 0.60.2",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
@@ -4668,7 +4672,7 @@ dependencies = [
|
|||||||
"http 1.4.1",
|
"http 1.4.1",
|
||||||
"http-body 1.0.1",
|
"http-body 1.0.1",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper 1.10.0",
|
"hyper 1.10.1",
|
||||||
"hyper-rustls 0.27.9",
|
"hyper-rustls 0.27.9",
|
||||||
"hyper-tls",
|
"hyper-tls",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
@@ -4714,7 +4718,7 @@ dependencies = [
|
|||||||
"http 1.4.1",
|
"http 1.4.1",
|
||||||
"http-body 1.0.1",
|
"http-body 1.0.1",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper 1.10.0",
|
"hyper 1.10.1",
|
||||||
"hyper-rustls 0.27.9",
|
"hyper-rustls 0.27.9",
|
||||||
"hyper-tls",
|
"hyper-tls",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
@@ -4817,9 +4821,9 @@ checksum = "323c417e1d9665a65b263ec744ba09030cfb277e9daa0b018a4ab62e57bc8189"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rpassword"
|
name = "rpassword"
|
||||||
version = "7.5.3"
|
version = "7.5.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "835a57a69104632d64deb0df2e09a69945cd7a6eab4070fc9b1d7e50cf6c3edc"
|
checksum = "2da316a15f47e3d053de9cb2c439650bd8fa4aaeb9365f2e5f27f492ff73c196"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"rtoolbox",
|
"rtoolbox",
|
||||||
@@ -4944,9 +4948,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-native-certs"
|
name = "rustls-native-certs"
|
||||||
version = "0.8.3"
|
version = "0.8.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63"
|
checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"openssl-probe",
|
"openssl-probe",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
@@ -5034,15 +5038,6 @@ dependencies = [
|
|||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "scc"
|
|
||||||
version = "2.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "46e6f046b7fef48e2660c57ed794263155d713de679057f2d0c169bfc6e756cc"
|
|
||||||
dependencies = [
|
|
||||||
"sdd",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "schannel"
|
name = "schannel"
|
||||||
version = "0.1.29"
|
version = "0.1.29"
|
||||||
@@ -5121,12 +5116,6 @@ dependencies = [
|
|||||||
"untrusted",
|
"untrusted",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sdd"
|
|
||||||
version = "3.0.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "secrecy"
|
name = "secrecy"
|
||||||
version = "0.10.3"
|
version = "0.10.3"
|
||||||
@@ -5320,9 +5309,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_with"
|
name = "serde_with"
|
||||||
version = "3.20.0"
|
version = "3.21.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e72c1c2cb7b223fafb600a619537a871c2818583d619401b785e7c0b746ccde2"
|
checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"bs58",
|
"bs58",
|
||||||
@@ -5340,9 +5329,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_with_macros"
|
name = "serde_with_macros"
|
||||||
version = "3.20.0"
|
version = "3.21.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b90c488738ecb4fb0262f41f43bc40efc5868d9fb744319ddf5f5317f417bfac"
|
checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling 0.23.0",
|
"darling 0.23.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@@ -5365,24 +5354,23 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serial_test"
|
name = "serial_test"
|
||||||
version = "3.4.0"
|
version = "3.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "911bd979bf1070a3f3aa7b691a3b3e9968f339ceeec89e08c280a8a22207a32f"
|
checksum = "699f4197115b8a7e7ff19c9a315a4bd6fffec26cc4626ef45ecaea389e081c6d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-executor",
|
"futures-executor",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"log",
|
"log",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"scc",
|
|
||||||
"serial_test_derive",
|
"serial_test_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serial_test_derive"
|
name = "serial_test_derive"
|
||||||
version = "3.4.0"
|
version = "3.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0a7d91949b85b0d2fb687445e448b40d322b6b3e4af6b44a29b21d9a5f33e6d9"
|
checksum = "94e153fc76e1c6a068703d6d29c508a0b15c061c4b7e43da59cc097bc342673c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -5460,6 +5448,12 @@ version = "1.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shlex"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sigchld"
|
name = "sigchld"
|
||||||
version = "0.2.4"
|
version = "0.2.4"
|
||||||
@@ -5582,9 +5576,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.6.3"
|
version = "0.6.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
|
checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
@@ -6019,7 +6013,7 @@ dependencies = [
|
|||||||
"parking_lot",
|
"parking_lot",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"socket2 0.6.3",
|
"socket2 0.6.4",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
@@ -6130,13 +6124,13 @@ dependencies = [
|
|||||||
"http 1.4.1",
|
"http 1.4.1",
|
||||||
"http-body 1.0.1",
|
"http-body 1.0.1",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper 1.10.0",
|
"hyper 1.10.1",
|
||||||
"hyper-timeout",
|
"hyper-timeout",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project",
|
"pin-project",
|
||||||
"rustls-native-certs",
|
"rustls-native-certs",
|
||||||
"socket2 0.6.3",
|
"socket2 0.6.4",
|
||||||
"sync_wrapper",
|
"sync_wrapper",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls 0.26.4",
|
"tokio-rustls 0.26.4",
|
||||||
@@ -6311,9 +6305,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.20.0"
|
version = "1.20.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de"
|
checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typespec"
|
name = "typespec"
|
||||||
@@ -6386,9 +6380,9 @@ checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-segmentation"
|
name = "unicode-segmentation"
|
||||||
version = "1.13.2"
|
version = "1.13.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c"
|
checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "unicode-width"
|
||||||
@@ -6523,9 +6517,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.23.1"
|
version = "1.23.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76"
|
checksum = "d258b83ceec21034727ecee8c382cfa6c3e133699b0742c64571814fb420c9f7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.4.2",
|
"getrandom 0.4.2",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
@@ -7418,9 +7412,9 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yoke"
|
name = "yoke"
|
||||||
version = "0.8.2"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca"
|
checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"stable_deref_trait",
|
"stable_deref_trait",
|
||||||
"yoke-derive",
|
"yoke-derive",
|
||||||
@@ -7441,18 +7435,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.8.49"
|
version = "0.8.50"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bce33a6288fa3f072a8c2c7d0f2fdbb90e28298f0135c1f99b96c3db2efcc60b"
|
checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerocopy-derive",
|
"zerocopy-derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy-derive"
|
name = "zerocopy-derive"
|
||||||
version = "0.8.49"
|
version = "0.8.50"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8fd425244944f4ab65ccff928e7323354c5a018c75838362fdce749dfad2ee1e"
|
checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "coyote-ai"
|
name = "coyote-ai"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
authors = ["Alex Clarke <alex.j.tusa@gmail.com>"]
|
authors = ["Alex Clarke <alex.j.tusa@gmail.com>"]
|
||||||
description = "An all-in-one, batteries included LLM CLI Tool"
|
description = "An all-in-one, batteries included LLM CLI Tool"
|
||||||
|
|||||||
@@ -507,7 +507,9 @@ open_link() {
|
|||||||
|
|
||||||
guard_operation() {
|
guard_operation() {
|
||||||
if [[ -z "$AUTO_CONFIRM" && -z "$LLM_AGENT_VAR_AUTO_CONFIRM" ]]; then
|
if [[ -z "$AUTO_CONFIRM" && -z "$LLM_AGENT_VAR_AUTO_CONFIRM" ]]; then
|
||||||
ans="$(confirm "${1:-Are you sure you want to continue?}")"
|
# 2>/dev/tty: keep the prompt off the host-captured stderr pipe so it
|
||||||
|
# can't leak into tool_call_error JSON when the wrapped command fails.
|
||||||
|
ans="$(confirm "${1:-Are you sure you want to continue?}" 2>/dev/tty)"
|
||||||
|
|
||||||
if [[ "$ans" == 0 ]]; then
|
if [[ "$ans" == 0 ]]; then
|
||||||
error "Operation aborted!" 2>&1
|
error "Operation aborted!" 2>&1
|
||||||
@@ -657,7 +659,8 @@ guard_path() {
|
|||||||
confirmation_prompt="$2"
|
confirmation_prompt="$2"
|
||||||
|
|
||||||
if [[ ! "$path" == "$(pwd)"* && -z "$AUTO_CONFIRM" && -z "$LLM_AGENT_VAR_AUTO_CONFIRM" ]]; then
|
if [[ ! "$path" == "$(pwd)"* && -z "$AUTO_CONFIRM" && -z "$LLM_AGENT_VAR_AUTO_CONFIRM" ]]; then
|
||||||
ans="$(confirm "$confirmation_prompt")"
|
# 2>/dev/tty: see guard_operation — prevents prompt text leaking via captured stderr.
|
||||||
|
ans="$(confirm "$confirmation_prompt" 2>/dev/tty)"
|
||||||
|
|
||||||
if [[ "$ans" == 0 ]]; then
|
if [[ "$ans" == 0 ]]; then
|
||||||
error "Operation aborted!" >&2
|
error "Operation aborted!" >&2
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
---
|
||||||
|
skills_enabled: false
|
||||||
|
---
|
||||||
As a professional Prompt Engineer, your role is to create effective and innovative prompts for interacting with AI models.
|
As a professional Prompt Engineer, your role is to create effective and innovative prompts for interacting with AI models.
|
||||||
|
|
||||||
Your core skills include:
|
Your core skills include:
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
---
|
||||||
|
skills_enabled: false
|
||||||
|
---
|
||||||
Create a concise, 3-6 word title.
|
Create a concise, 3-6 word title.
|
||||||
|
|
||||||
**Notes**:
|
**Notes**:
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
---
|
||||||
|
skills_enabled: false
|
||||||
|
---
|
||||||
Provide a terse, single sentence description of the given shell command.
|
Provide a terse, single sentence description of the given shell command.
|
||||||
Describe each argument and option of the command.
|
Describe each argument and option of the command.
|
||||||
Provide short responses in about 80 words.
|
Provide short responses in about 80 words.
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
---
|
||||||
|
skills_enabled: false
|
||||||
|
---
|
||||||
Provide only {{__shell__}} commands for {{__os_distro__}} without any description.
|
Provide only {{__shell__}} commands for {{__os_distro__}} without any description.
|
||||||
Ensure the output is a valid {{__shell__}} command.
|
Ensure the output is a valid {{__shell__}} command.
|
||||||
If there is a lack of details, provide most logical solution.
|
If there is a lack of details, provide most logical solution.
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ auto_continue: false # Enable automatic continuation when incomplete
|
|||||||
max_auto_continues: 10 # Maximum number of automatic continuations before stopping
|
max_auto_continues: 10 # Maximum number of automatic continuations before stopping
|
||||||
inject_todo_instructions: true # Inject the default todo tool usage instructions into the agent's system prompt
|
inject_todo_instructions: true # Inject the default todo tool usage instructions into the agent's system prompt
|
||||||
continuation_prompt: null # Custom prompt used when auto-continuing (optional; uses default if null)
|
continuation_prompt: null # Custom prompt used when auto-continuing (optional; uses default if null)
|
||||||
|
inject_skill_instructions: true # Inject a short hint pointing the model at `skill__list` when skills are enabled
|
||||||
|
# (default: true). Suppressed automatically when no skills are available.
|
||||||
|
skill_instructions: null # Custom text for the skill hint (optional; uses built-in default if null)
|
||||||
# Sub-Agent Spawning System
|
# Sub-Agent Spawning System
|
||||||
# Enable this agent to spawn and manage child agents in parallel.
|
# Enable this agent to spawn and manage child agents in parallel.
|
||||||
# See https://github.com/Dark-Alex-17/coyote/wiki/Agents for detailed documentation.
|
# See https://github.com/Dark-Alex-17/coyote/wiki/Agents for detailed documentation.
|
||||||
|
|||||||
@@ -162,6 +162,10 @@ auto_continue: false # Enable automatic continuation when incomplet
|
|||||||
max_auto_continues: 10 # Maximum number of automatic continuations before stopping (default: 10)
|
max_auto_continues: 10 # Maximum number of automatic continuations before stopping (default: 10)
|
||||||
inject_todo_instructions: true # Inject default todo usage instructions into the system prompt (default: true)
|
inject_todo_instructions: true # Inject default todo usage instructions into the system prompt (default: true)
|
||||||
continuation_prompt: null # Custom prompt used when auto-continuing. If null, uses built-in default
|
continuation_prompt: null # Custom prompt used when auto-continuing. If null, uses built-in default
|
||||||
|
inject_skill_instructions: true # Inject a short hint pointing the model at `skill__list` when skills are enabled in
|
||||||
|
# this context. Only injected if `function_calling_support`, `skills_enabled`, and the
|
||||||
|
# effective enabled skill set is non-empty (default: true).
|
||||||
|
skill_instructions: null # Custom text used for the skill hint when injected. If null, uses built-in default.
|
||||||
|
|
||||||
# ---- Session ----
|
# ---- Session ----
|
||||||
# See the [Session documentation](https://github.com/Dark-Alex-17/coyote/wiki/Sessions) for more information
|
# See the [Session documentation](https://github.com/Dark-Alex-17/coyote/wiki/Sessions) for more information
|
||||||
|
|||||||
@@ -30,5 +30,8 @@ auto_continue: false # Enable automatic continuation when incom
|
|||||||
max_auto_continues: 10 # Maximum number of automatic continuations before stopping (default: 10)
|
max_auto_continues: 10 # Maximum number of automatic continuations before stopping (default: 10)
|
||||||
inject_todo_instructions: true # Inject default todo tool usage instructions into the system prompt (default: true)
|
inject_todo_instructions: true # Inject default todo tool usage instructions into the system prompt (default: true)
|
||||||
continuation_prompt: null # Custom prompt used when auto-continuing. If null, uses built-in default
|
continuation_prompt: null # Custom prompt used when auto-continuing. If null, uses built-in default
|
||||||
|
inject_skill_instructions: true # Inject a short hint pointing the model at `skill__list` when skills are enabled
|
||||||
|
# (default: true). Suppressed automatically when no skills are available.
|
||||||
|
skill_instructions: null # Custom text for the skill hint (optional; uses built-in default if null)
|
||||||
---
|
---
|
||||||
You are an expert at doing things. This is where you write the instructions for the role.
|
You are an expert at doing things. This is where you write the instructions for the role.
|
||||||
|
|||||||
@@ -63,6 +63,9 @@ enabled_skills:
|
|||||||
- code-review
|
- code-review
|
||||||
- git-master
|
- git-master
|
||||||
- ai-slop-remover
|
- ai-slop-remover
|
||||||
|
inject_skill_instructions: true # Inject a hint pointing the model at `skill__list`. Defaults to true; suppressed
|
||||||
|
# automatically when no skills are available.
|
||||||
|
skill_instructions: null # Custom text for the skill hint (optional; uses the built-in default if omitted).
|
||||||
|
|
||||||
conversation_starters: # Suggested prompts surfaced in the UI
|
conversation_starters: # Suggested prompts surfaced in the UI
|
||||||
- "Research the current state of WebAssembly outside the browser"
|
- "Research the current state of WebAssembly outside the browser"
|
||||||
@@ -173,8 +176,12 @@ nodes:
|
|||||||
# catches violations at load time). `skills_enabled: false` would
|
# catches violations at load time). `skills_enabled: false` would
|
||||||
# disable skills entirely for this node (no meta-tools exposed).
|
# disable skills entirely for this node (no meta-tools exposed).
|
||||||
# Nothing is auto-loaded: the model decides when to load a skill.
|
# Nothing is auto-loaded: the model decides when to load a skill.
|
||||||
|
skills_enabled: true # Whether skills are enabled on this llm node; defaults to 'true'
|
||||||
enabled_skills:
|
enabled_skills:
|
||||||
- ai-slop-remover
|
- ai-slop-remover
|
||||||
|
inject_skill_instructions: true # Override skill-hint injection for just this node. Falls back to
|
||||||
|
# agent/graph/global default when omitted.
|
||||||
|
skill_instructions: null # Per-node skill-hint text override; uses the built-in default when omitted.
|
||||||
output_schema: # Optional JSON Schema. The output is parsed to JSON
|
output_schema: # Optional JSON Schema. The output is parsed to JSON
|
||||||
type: object # and its top-level object keys auto-merge into state
|
type: object # and its top-level object keys auto-merge into state
|
||||||
properties: # (so `topic` / `needs_deep_dive` become {{topic}} etc).
|
properties: # (so `topic` / `needs_deep_dive` become {{topic}} etc).
|
||||||
|
|||||||
@@ -464,6 +464,14 @@ impl Agent {
|
|||||||
self.config.continuation_prompt.clone()
|
self.config.continuation_prompt.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn inject_skill_instructions(&self) -> bool {
|
||||||
|
self.config.inject_skill_instructions
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn skill_instructions_value(&self) -> Option<String> {
|
||||||
|
self.config.skill_instructions.clone()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn can_spawn_agents(&self) -> bool {
|
pub fn can_spawn_agents(&self) -> bool {
|
||||||
self.config.can_spawn_agents
|
self.config.can_spawn_agents
|
||||||
}
|
}
|
||||||
@@ -625,6 +633,10 @@ pub struct AgentConfig {
|
|||||||
pub inject_todo_instructions: bool,
|
pub inject_todo_instructions: bool,
|
||||||
#[serde(default = "default_true")]
|
#[serde(default = "default_true")]
|
||||||
pub inject_spawn_instructions: bool,
|
pub inject_spawn_instructions: bool,
|
||||||
|
#[serde(default = "default_true")]
|
||||||
|
pub inject_skill_instructions: bool,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub skill_instructions: Option<String>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub compression_threshold: Option<usize>,
|
pub compression_threshold: Option<usize>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
@@ -704,6 +716,8 @@ impl AgentConfig {
|
|||||||
mcp_servers: graph.mcp_servers.clone(),
|
mcp_servers: graph.mcp_servers.clone(),
|
||||||
skills_enabled: graph.skills_enabled,
|
skills_enabled: graph.skills_enabled,
|
||||||
enabled_skills: graph.enabled_skills.clone(),
|
enabled_skills: graph.enabled_skills.clone(),
|
||||||
|
inject_skill_instructions: graph.inject_skill_instructions.unwrap_or(true),
|
||||||
|
skill_instructions: graph.skill_instructions.clone(),
|
||||||
conversation_starters: graph.conversation_starters.clone(),
|
conversation_starters: graph.conversation_starters.clone(),
|
||||||
variables: graph.variables.clone(),
|
variables: graph.variables.clone(),
|
||||||
can_spawn_agents: graph.has_agent_node(),
|
can_spawn_agents: graph.has_agent_node(),
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ pub struct AppConfig {
|
|||||||
pub max_auto_continues: usize,
|
pub max_auto_continues: usize,
|
||||||
pub inject_todo_instructions: bool,
|
pub inject_todo_instructions: bool,
|
||||||
pub continuation_prompt: Option<String>,
|
pub continuation_prompt: Option<String>,
|
||||||
|
pub inject_skill_instructions: bool,
|
||||||
|
pub skill_instructions: Option<String>,
|
||||||
|
|
||||||
pub repl_prelude: Option<String>,
|
pub repl_prelude: Option<String>,
|
||||||
pub cmd_prelude: Option<String>,
|
pub cmd_prelude: Option<String>,
|
||||||
@@ -118,6 +120,8 @@ impl Default for AppConfig {
|
|||||||
max_auto_continues: 10,
|
max_auto_continues: 10,
|
||||||
inject_todo_instructions: true,
|
inject_todo_instructions: true,
|
||||||
continuation_prompt: None,
|
continuation_prompt: None,
|
||||||
|
inject_skill_instructions: true,
|
||||||
|
skill_instructions: None,
|
||||||
|
|
||||||
repl_prelude: None,
|
repl_prelude: None,
|
||||||
cmd_prelude: None,
|
cmd_prelude: None,
|
||||||
@@ -185,6 +189,8 @@ impl AppConfig {
|
|||||||
max_auto_continues: config.max_auto_continues,
|
max_auto_continues: config.max_auto_continues,
|
||||||
inject_todo_instructions: config.inject_todo_instructions,
|
inject_todo_instructions: config.inject_todo_instructions,
|
||||||
continuation_prompt: config.continuation_prompt,
|
continuation_prompt: config.continuation_prompt,
|
||||||
|
inject_skill_instructions: config.inject_skill_instructions,
|
||||||
|
skill_instructions: config.skill_instructions,
|
||||||
|
|
||||||
repl_prelude: config.repl_prelude,
|
repl_prelude: config.repl_prelude,
|
||||||
cmd_prelude: config.cmd_prelude,
|
cmd_prelude: config.cmd_prelude,
|
||||||
|
|||||||
+6
-2
@@ -6,7 +6,7 @@ mod install_remote;
|
|||||||
mod macros;
|
mod macros;
|
||||||
mod mcp_factory;
|
mod mcp_factory;
|
||||||
pub(crate) mod paths;
|
pub(crate) mod paths;
|
||||||
mod prompts;
|
pub(crate) mod prompts;
|
||||||
mod rag_cache;
|
mod rag_cache;
|
||||||
mod request_context;
|
mod request_context;
|
||||||
mod role;
|
mod role;
|
||||||
@@ -28,7 +28,7 @@ pub use self::app_state::AppState;
|
|||||||
pub use self::input::Input;
|
pub use self::input::Input;
|
||||||
pub use self::install_remote::{install_remote, install_remote_from_repl_args};
|
pub use self::install_remote::{install_remote, install_remote_from_repl_args};
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
pub use self::request_context::{RenderMode, RequestContext};
|
pub use self::request_context::{RenderMode, RequestContext, should_inject_skill_instructions};
|
||||||
pub use self::role::{
|
pub use self::role::{
|
||||||
CODE_ROLE, CREATE_TITLE_ROLE, EXPLAIN_SHELL_ROLE, Role, RoleLike, SHELL_ROLE,
|
CODE_ROLE, CREATE_TITLE_ROLE, EXPLAIN_SHELL_ROLE, Role, RoleLike, SHELL_ROLE,
|
||||||
};
|
};
|
||||||
@@ -214,6 +214,8 @@ pub struct Config {
|
|||||||
pub max_auto_continues: usize,
|
pub max_auto_continues: usize,
|
||||||
pub inject_todo_instructions: bool,
|
pub inject_todo_instructions: bool,
|
||||||
pub continuation_prompt: Option<String>,
|
pub continuation_prompt: Option<String>,
|
||||||
|
pub inject_skill_instructions: bool,
|
||||||
|
pub skill_instructions: Option<String>,
|
||||||
|
|
||||||
pub repl_prelude: Option<String>,
|
pub repl_prelude: Option<String>,
|
||||||
pub cmd_prelude: Option<String>,
|
pub cmd_prelude: Option<String>,
|
||||||
@@ -280,6 +282,8 @@ impl Default for Config {
|
|||||||
max_auto_continues: 10,
|
max_auto_continues: 10,
|
||||||
inject_todo_instructions: true,
|
inject_todo_instructions: true,
|
||||||
continuation_prompt: None,
|
continuation_prompt: None,
|
||||||
|
inject_skill_instructions: true,
|
||||||
|
skill_instructions: None,
|
||||||
|
|
||||||
repl_prelude: None,
|
repl_prelude: None,
|
||||||
cmd_prelude: None,
|
cmd_prelude: None,
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
use indoc::indoc;
|
use indoc::indoc;
|
||||||
|
|
||||||
|
pub(crate) const DEFAULT_SKILL_INSTRUCTIONS: &str = indoc! {"
|
||||||
|
## Skills
|
||||||
|
Specialized skills may be available in this context. Call `skill__list` early in a task to
|
||||||
|
discover any that match the work, then `skill__load` the relevant ones. Their instructions and
|
||||||
|
granted tools will become active for subsequent turns. Call `skill__unload` when their work is
|
||||||
|
complete to keep the context lean."
|
||||||
|
};
|
||||||
|
|
||||||
pub(in crate::config) const DEFAULT_TODO_INSTRUCTIONS: &str = indoc! {"
|
pub(in crate::config) const DEFAULT_TODO_INSTRUCTIONS: &str = indoc! {"
|
||||||
## Task Tracking
|
## Task Tracking
|
||||||
You have built-in task tracking tools. Use them to track your progress:
|
You have built-in task tracking tools. Use them to track your progress:
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ use indoc::formatdoc;
|
|||||||
use inquire::{Confirm, MultiSelect, Text, list_option::ListOption, validator::Validation};
|
use inquire::{Confirm, MultiSelect, Text, list_option::ListOption, validator::Validation};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
|
use prompts::DEFAULT_SKILL_INSTRUCTIONS;
|
||||||
use std::collections::{BTreeSet, HashMap, HashSet};
|
use std::collections::{BTreeSet, HashMap, HashSet};
|
||||||
use std::fs::{File, OpenOptions, read_dir, read_to_string, remove_dir_all, remove_file};
|
use std::fs::{File, OpenOptions, read_dir, read_to_string, remove_dir_all, remove_file};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
@@ -53,6 +54,20 @@ pub struct AutoContinueConfig {
|
|||||||
pub continuation_prompt: Option<String>,
|
pub continuation_prompt: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct SkillInstructionsConfig {
|
||||||
|
pub inject: bool,
|
||||||
|
pub instructions: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Must stay in sync with the predicate that registers `skill__*` tools in `rebuild_tool_scope`
|
||||||
|
/// (and in `graph::llm::run_llm_node`). Telling the model to call tools that are not exposed
|
||||||
|
/// is a footgun. `compatible_enabled` is the post-filter universe that `skill__list` would
|
||||||
|
/// actually return (cascade-allowed AND surviving `Skill::is_compatible` for current
|
||||||
|
/// `mcp_server_support`), so an empty set means the hint has nothing to point at.
|
||||||
|
pub fn should_inject_skill_instructions(app: &AppConfig, policy: &SkillPolicy) -> bool {
|
||||||
|
app.function_calling_support && policy.skills_enabled && !policy.compatible_enabled.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||||
pub enum RenderMode {
|
pub enum RenderMode {
|
||||||
#[default]
|
#[default]
|
||||||
@@ -634,9 +649,62 @@ impl RequestContext {
|
|||||||
self.agent.as_ref(),
|
self.agent.as_ref(),
|
||||||
self.session.as_ref(),
|
self.session.as_ref(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
if should_inject_skill_instructions(app, &policy) {
|
||||||
|
let config = self.skill_instructions_config();
|
||||||
|
|
||||||
|
if config.inject {
|
||||||
|
let separator = if role.is_empty_prompt() { "" } else { "\n\n" };
|
||||||
|
|
||||||
|
role.append_to_prompt(separator);
|
||||||
|
role.append_to_prompt(
|
||||||
|
config
|
||||||
|
.instructions
|
||||||
|
.as_deref()
|
||||||
|
.unwrap_or(DEFAULT_SKILL_INSTRUCTIONS),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(self.skill_registry.effective_role(&role, &policy))
|
Ok(self.skill_registry.effective_role(&role, &policy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn skill_instructions_config(&self) -> SkillInstructionsConfig {
|
||||||
|
if let Some(agent) = &self.agent {
|
||||||
|
return SkillInstructionsConfig {
|
||||||
|
inject: agent.inject_skill_instructions(),
|
||||||
|
instructions: agent.skill_instructions_value(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let app = &self.app.config;
|
||||||
|
let inject = self
|
||||||
|
.session
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|s| s.inject_skill_instructions())
|
||||||
|
.or_else(|| {
|
||||||
|
self.role
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|r| r.inject_skill_instructions())
|
||||||
|
})
|
||||||
|
.unwrap_or(app.inject_skill_instructions);
|
||||||
|
let instructions = self
|
||||||
|
.session
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|s| s.skill_instructions().map(|v| v.to_string()))
|
||||||
|
.or_else(|| {
|
||||||
|
self.role
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|r| r.skill_instructions().map(|v| v.to_string()))
|
||||||
|
})
|
||||||
|
.or_else(|| app.skill_instructions.clone());
|
||||||
|
|
||||||
|
SkillInstructionsConfig {
|
||||||
|
inject,
|
||||||
|
instructions,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn auto_continue_config(&self) -> AutoContinueConfig {
|
pub fn auto_continue_config(&self) -> AutoContinueConfig {
|
||||||
if let Some(agent) = &self.agent {
|
if let Some(agent) = &self.agent {
|
||||||
return AutoContinueConfig {
|
return AutoContinueConfig {
|
||||||
@@ -1207,7 +1275,8 @@ impl RequestContext {
|
|||||||
.iter()
|
.iter()
|
||||||
.filter(|v| {
|
.filter(|v| {
|
||||||
(v.name.starts_with(USER_FUNCTION_PREFIX)
|
(v.name.starts_with(USER_FUNCTION_PREFIX)
|
||||||
|| v.name.starts_with(SKILL_FUNCTION_PREFIX))
|
|| (!matches!(role.skills_enabled(), Some(false))
|
||||||
|
&& v.name.starts_with(SKILL_FUNCTION_PREFIX)))
|
||||||
&& !existing.contains(&v.name)
|
&& !existing.contains(&v.name)
|
||||||
})
|
})
|
||||||
.cloned()
|
.cloned()
|
||||||
@@ -1707,7 +1776,7 @@ impl RequestContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let value = match key {
|
let value = match key {
|
||||||
"continuation_prompt" => raw_value,
|
"continuation_prompt" | "skill_instructions" => raw_value,
|
||||||
_ => {
|
_ => {
|
||||||
if raw_value.contains(char::is_whitespace) {
|
if raw_value.contains(char::is_whitespace) {
|
||||||
bail!("Usage: .set <key> <value>. If value is null, unset key.");
|
bail!("Usage: .set <key> <value>. If value is null, unset key.");
|
||||||
@@ -1907,6 +1976,22 @@ impl RequestContext {
|
|||||||
self.update_app_config(|app| app.continuation_prompt = value);
|
self.update_app_config(|app| app.continuation_prompt = value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"inject_skill_instructions" => {
|
||||||
|
let value: bool = value.parse().with_context(|| "Invalid value")?;
|
||||||
|
if let Some(session) = self.session.as_mut() {
|
||||||
|
session.set_inject_skill_instructions(Some(value));
|
||||||
|
} else {
|
||||||
|
self.update_app_config(|app| app.inject_skill_instructions = value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"skill_instructions" => {
|
||||||
|
let value: Option<String> = super::parse_value(value)?;
|
||||||
|
if let Some(session) = self.session.as_mut() {
|
||||||
|
session.set_skill_instructions(value);
|
||||||
|
} else {
|
||||||
|
self.update_app_config(|app| app.skill_instructions = value);
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => bail!("Unknown key '{key}'"),
|
_ => bail!("Unknown key '{key}'"),
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -2006,6 +2091,8 @@ impl RequestContext {
|
|||||||
"enabled_tools",
|
"enabled_tools",
|
||||||
"enabled_mcp_servers",
|
"enabled_mcp_servers",
|
||||||
"inject_todo_instructions",
|
"inject_todo_instructions",
|
||||||
|
"inject_skill_instructions",
|
||||||
|
"skill_instructions",
|
||||||
"max_auto_continues",
|
"max_auto_continues",
|
||||||
"save_session",
|
"save_session",
|
||||||
"compression_threshold",
|
"compression_threshold",
|
||||||
@@ -2172,6 +2259,11 @@ impl RequestContext {
|
|||||||
super::complete_bool(config.inject_instructions)
|
super::complete_bool(config.inject_instructions)
|
||||||
}
|
}
|
||||||
"continuation_prompt" => vec!["null".to_string()],
|
"continuation_prompt" => vec!["null".to_string()],
|
||||||
|
"inject_skill_instructions" => {
|
||||||
|
let config = self.skill_instructions_config();
|
||||||
|
super::complete_bool(config.inject)
|
||||||
|
}
|
||||||
|
"skill_instructions" => vec!["null".to_string()],
|
||||||
_ => vec![],
|
_ => vec![],
|
||||||
};
|
};
|
||||||
values = candidates.into_iter().map(|v| (v, None)).collect();
|
values = candidates.into_iter().map(|v| (v, None)).collect();
|
||||||
@@ -2981,11 +3073,12 @@ mod tests {
|
|||||||
use super::super::mcp_factory::McpFactory;
|
use super::super::mcp_factory::McpFactory;
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::config::AppState;
|
use crate::config::AppState;
|
||||||
use crate::function::ToolCall;
|
use crate::function::{ToolCall, skill};
|
||||||
use crate::mcp::{McpServer, McpServersConfig, McpTransportType};
|
use crate::mcp::{McpServer, McpServersConfig, McpTransportType};
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
use crate::utils::get_env_name;
|
use crate::utils::get_env_name;
|
||||||
use crate::vault::Vault;
|
use crate::vault::Vault;
|
||||||
|
use serde_json::json;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::{create_dir_all, remove_dir_all, write};
|
use std::fs::{create_dir_all, remove_dir_all, write};
|
||||||
@@ -3123,6 +3216,108 @@ mod tests {
|
|||||||
assert_eq!(extracted.name(), "");
|
assert_eq!(extracted.name(), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_inject_skill_instructions_requires_function_calling() {
|
||||||
|
let app = AppConfig {
|
||||||
|
function_calling_support: false,
|
||||||
|
..AppConfig::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let policy = SkillPolicy {
|
||||||
|
skills_enabled: true,
|
||||||
|
enabled: ["a".to_string()].into_iter().collect(),
|
||||||
|
compatible_enabled: ["a".to_string()].into_iter().collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(!should_inject_skill_instructions(&app, &policy));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_inject_skill_instructions_requires_skills_enabled() {
|
||||||
|
let app = AppConfig {
|
||||||
|
function_calling_support: true,
|
||||||
|
..AppConfig::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let policy = SkillPolicy {
|
||||||
|
skills_enabled: false,
|
||||||
|
enabled: ["a".to_string()].into_iter().collect(),
|
||||||
|
compatible_enabled: ["a".to_string()].into_iter().collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(!should_inject_skill_instructions(&app, &policy));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_inject_skill_instructions_suppresses_when_no_compatible_skills() {
|
||||||
|
let app = AppConfig {
|
||||||
|
function_calling_support: true,
|
||||||
|
..AppConfig::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
// `enabled` has names, but none survive the compatibility filter — hint must suppress.
|
||||||
|
let policy = SkillPolicy {
|
||||||
|
skills_enabled: true,
|
||||||
|
enabled: ["a".to_string()].into_iter().collect(),
|
||||||
|
compatible_enabled: Default::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(!should_inject_skill_instructions(&app, &policy));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_inject_skill_instructions_when_all_conditions_met() {
|
||||||
|
let app = AppConfig {
|
||||||
|
function_calling_support: true,
|
||||||
|
..AppConfig::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let policy = SkillPolicy {
|
||||||
|
skills_enabled: true,
|
||||||
|
enabled: ["a".to_string()].into_iter().collect(),
|
||||||
|
compatible_enabled: ["a".to_string()].into_iter().collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(should_inject_skill_instructions(&app, &policy));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn skill_instructions_config_falls_back_to_app_default() {
|
||||||
|
let ctx = create_test_ctx();
|
||||||
|
|
||||||
|
let cfg = ctx.skill_instructions_config();
|
||||||
|
|
||||||
|
assert!(cfg.inject);
|
||||||
|
assert!(cfg.instructions.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn skill_instructions_config_respects_role_disable() {
|
||||||
|
let mut ctx = create_test_ctx();
|
||||||
|
let role = Role::new("r", "---\ninject_skill_instructions: false\n---\nhello");
|
||||||
|
ctx.use_role_obj(role).unwrap();
|
||||||
|
|
||||||
|
let cfg = ctx.skill_instructions_config();
|
||||||
|
|
||||||
|
assert!(!cfg.inject);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn skill_instructions_config_session_overrides_role() {
|
||||||
|
let mut ctx = create_test_ctx();
|
||||||
|
let role = Role::new("r", "---\ninject_skill_instructions: false\n---\nhello");
|
||||||
|
ctx.use_role_obj(role).unwrap();
|
||||||
|
let mut session = Session::default();
|
||||||
|
session.set_inject_skill_instructions(Some(true));
|
||||||
|
session.set_skill_instructions(Some("custom hint".into()));
|
||||||
|
ctx.session = Some(session);
|
||||||
|
|
||||||
|
let cfg = ctx.skill_instructions_config();
|
||||||
|
|
||||||
|
assert!(cfg.inject);
|
||||||
|
assert_eq!(cfg.instructions.as_deref(), Some("custom hint"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exit_session_clears_session() {
|
fn exit_session_clears_session() {
|
||||||
let mut ctx = create_test_ctx();
|
let mut ctx = create_test_ctx();
|
||||||
@@ -3448,6 +3643,182 @@ mod tests {
|
|||||||
assert!(!names.contains(&"todo__done"));
|
assert!(!names.contains(&"todo__done"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn select_functions_re_adds_skill_tools_when_role_skills_enabled_unset() {
|
||||||
|
let mut ctx = create_test_ctx();
|
||||||
|
ctx.tool_scope.functions.append_skill_functions();
|
||||||
|
|
||||||
|
let mut role = Role::new("r", "p");
|
||||||
|
role.set_enabled_tools(Some(vec!["foo".to_string()]));
|
||||||
|
|
||||||
|
let fns = ctx.select_functions(&role).unwrap();
|
||||||
|
let names: Vec<&str> = fns.iter().map(|f| f.name.as_str()).collect();
|
||||||
|
assert!(names.contains(&"skill__list"));
|
||||||
|
assert!(names.contains(&"skill__load"));
|
||||||
|
assert!(names.contains(&"skill__unload"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn select_functions_suppresses_skill_tools_when_role_skills_enabled_false() {
|
||||||
|
let mut ctx = create_test_ctx();
|
||||||
|
ctx.tool_scope.functions.append_skill_functions();
|
||||||
|
ctx.tool_scope.functions.append_todo_functions();
|
||||||
|
|
||||||
|
let mut role = Role::new("r", "---\nskills_enabled: false\n---\np");
|
||||||
|
role.set_enabled_tools(Some(vec!["todo__init".to_string()]));
|
||||||
|
|
||||||
|
let fns = ctx.select_functions(&role).unwrap();
|
||||||
|
let names: Vec<&str> = fns.iter().map(|f| f.name.as_str()).collect();
|
||||||
|
assert!(names.contains(&"todo__init"));
|
||||||
|
assert!(!names.contains(&"skill__list"));
|
||||||
|
assert!(!names.contains(&"skill__load"));
|
||||||
|
assert!(!names.contains(&"skill__unload"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn select_functions_still_re_adds_user_tools_when_role_skills_enabled_false() {
|
||||||
|
let mut ctx = create_test_ctx();
|
||||||
|
ctx.tool_scope.functions.append_user_interaction_functions();
|
||||||
|
ctx.tool_scope.functions.append_skill_functions();
|
||||||
|
|
||||||
|
let mut role = Role::new("r", "---\nskills_enabled: false\n---\np");
|
||||||
|
role.set_enabled_tools(Some(vec!["foo".to_string()]));
|
||||||
|
|
||||||
|
let fns = ctx.select_functions(&role).unwrap();
|
||||||
|
let names: Vec<&str> = fns.iter().map(|f| f.name.as_str()).collect();
|
||||||
|
assert!(names.contains(&"user__ask"));
|
||||||
|
assert!(!names.contains(&"skill__list"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn select_functions_re_adds_skill_tools_when_agent_skills_enabled_not_false() {
|
||||||
|
let _guard = TestConfigDirGuard::new();
|
||||||
|
let mut ctx = create_test_ctx();
|
||||||
|
let app = ctx.app.config.clone();
|
||||||
|
let agent_name = format!(
|
||||||
|
"test_skill_agent_{}",
|
||||||
|
SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_nanos()
|
||||||
|
);
|
||||||
|
let agent_dir = paths::agent_data_dir(&agent_name);
|
||||||
|
create_dir_all(&agent_dir).unwrap();
|
||||||
|
write(
|
||||||
|
agent_dir.join("graph.yaml"),
|
||||||
|
format!(
|
||||||
|
"name: {agent_name}\nversion: \"1.0\"\nstart: done\nnodes:\n done:\n type: end\n output: ok\n"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let abort = utils::create_abort_signal();
|
||||||
|
run_async(ctx.use_agent(&app, &agent_name, None, abort)).unwrap();
|
||||||
|
ctx.tool_scope.functions.append_skill_functions();
|
||||||
|
|
||||||
|
let mut role = Role::new("r", "p");
|
||||||
|
role.set_enabled_tools(Some(vec!["foo".to_string()]));
|
||||||
|
|
||||||
|
let fns = ctx.select_functions(&role).unwrap();
|
||||||
|
let names: Vec<&str> = fns.iter().map(|f| f.name.as_str()).collect();
|
||||||
|
assert!(names.contains(&"skill__list"));
|
||||||
|
assert!(names.contains(&"skill__load"));
|
||||||
|
assert!(names.contains(&"skill__unload"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fork_for_branch_clones_skill_registry() {
|
||||||
|
let mut ctx = create_test_ctx();
|
||||||
|
let skill = Skill::new("shared", "---\nauto_unload: false\n---\nbody");
|
||||||
|
ctx.skill_registry.insert(skill).unwrap();
|
||||||
|
|
||||||
|
let fork = ctx.fork_for_branch();
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
fork.skill_registry.is_loaded("shared"),
|
||||||
|
"Parallel branches must share loaded skills with parent"
|
||||||
|
);
|
||||||
|
assert!(ctx.skill_registry.is_loaded("shared"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn handle_skill_tool_returns_error_when_skills_disabled() {
|
||||||
|
let mut ctx = create_test_ctx();
|
||||||
|
let role = Role::new("r", "---\nskills_enabled: false\n---\np");
|
||||||
|
ctx.use_role_obj(role).unwrap();
|
||||||
|
|
||||||
|
let result = run_async(skill::handle_skill_tool(
|
||||||
|
&mut ctx,
|
||||||
|
"skill__list",
|
||||||
|
&json!({}),
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
result.get("error").is_some(),
|
||||||
|
"Expected error when skills are disabled, got: {result:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn handle_unload_returns_error_when_skill_not_loaded() {
|
||||||
|
let mut ctx = create_test_ctx();
|
||||||
|
|
||||||
|
let result = run_async(skill::handle_skill_tool(
|
||||||
|
&mut ctx,
|
||||||
|
"skill__unload",
|
||||||
|
&json!({"name": "ghost"}),
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
result.get("error").is_some(),
|
||||||
|
"Expected error when unloading unloaded skill, got: {result:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn select_functions_suppresses_skill_tools_when_agent_skills_enabled_false() {
|
||||||
|
let _guard = TestConfigDirGuard::new();
|
||||||
|
let mut ctx = create_test_ctx();
|
||||||
|
let app = ctx.app.config.clone();
|
||||||
|
let agent_name = format!(
|
||||||
|
"test_skill_agent_off_{}",
|
||||||
|
SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_nanos()
|
||||||
|
);
|
||||||
|
let agent_dir = paths::agent_data_dir(&agent_name);
|
||||||
|
create_dir_all(&agent_dir).unwrap();
|
||||||
|
write(
|
||||||
|
agent_dir.join("graph.yaml"),
|
||||||
|
format!(
|
||||||
|
"name: {agent_name}\nversion: \"1.0\"\nstart: done\nnodes:\n done:\n type: end\n output: ok\n"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let abort = utils::create_abort_signal();
|
||||||
|
run_async(ctx.use_agent(&app, &agent_name, None, abort)).unwrap();
|
||||||
|
ctx.agent
|
||||||
|
.as_mut()
|
||||||
|
.expect("agent loaded")
|
||||||
|
.set_skills_enabled(Some(false));
|
||||||
|
ctx.tool_scope.functions.append_skill_functions();
|
||||||
|
|
||||||
|
let mut role = Role::new("r", "p");
|
||||||
|
role.set_enabled_tools(Some(vec!["foo".to_string()]));
|
||||||
|
|
||||||
|
let fns = ctx.select_functions(&role).unwrap();
|
||||||
|
let names: Vec<&str> = fns.iter().map(|f| f.name.as_str()).collect();
|
||||||
|
assert!(!names.contains(&"skill__list"));
|
||||||
|
assert!(!names.contains(&"skill__load"));
|
||||||
|
assert!(!names.contains(&"skill__unload"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn select_enabled_mcp_servers_returns_empty_when_mcp_disabled() {
|
fn select_enabled_mcp_servers_returns_empty_when_mcp_disabled() {
|
||||||
let app_state = {
|
let app_state = {
|
||||||
@@ -3677,8 +4048,7 @@ mod tests {
|
|||||||
|
|
||||||
let input = Input::from_str(&ctx, "hello", None).unwrap();
|
let input = Input::from_str(&ctx, "hello", None).unwrap();
|
||||||
let app = Arc::clone(&ctx.app.config);
|
let app = Arc::clone(&ctx.app.config);
|
||||||
let tool_result =
|
let tool_result = ToolResult::new(crate::function::ToolCall::default(), json!({}));
|
||||||
ToolResult::new(crate::function::ToolCall::default(), serde_json::json!({}));
|
|
||||||
ctx.after_chat_completion(app.as_ref(), &input, "", &[tool_result])
|
ctx.after_chat_completion(app.as_ref(), &input, "", &[tool_result])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|||||||
@@ -79,6 +79,10 @@ pub struct Role {
|
|||||||
inject_todo_instructions: Option<bool>,
|
inject_todo_instructions: Option<bool>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
continuation_prompt: Option<String>,
|
continuation_prompt: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
inject_skill_instructions: Option<bool>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
skill_instructions: Option<String>,
|
||||||
|
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
model: Model,
|
model: Model,
|
||||||
@@ -124,6 +128,10 @@ impl Role {
|
|||||||
"continuation_prompt" => {
|
"continuation_prompt" => {
|
||||||
role.continuation_prompt = value.as_str().map(|v| v.to_string())
|
role.continuation_prompt = value.as_str().map(|v| v.to_string())
|
||||||
}
|
}
|
||||||
|
"inject_skill_instructions" => role.inject_skill_instructions = value.as_bool(),
|
||||||
|
"skill_instructions" => {
|
||||||
|
role.skill_instructions = value.as_str().map(|v| v.to_string())
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -189,6 +197,14 @@ impl Role {
|
|||||||
if let Some(continuation_prompt) = &self.continuation_prompt {
|
if let Some(continuation_prompt) = &self.continuation_prompt {
|
||||||
metadata.push(format!("continuation_prompt: {continuation_prompt}"));
|
metadata.push(format!("continuation_prompt: {continuation_prompt}"));
|
||||||
}
|
}
|
||||||
|
if let Some(inject_skill_instructions) = self.inject_skill_instructions {
|
||||||
|
metadata.push(format!(
|
||||||
|
"inject_skill_instructions: {inject_skill_instructions}"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if let Some(skill_instructions) = &self.skill_instructions {
|
||||||
|
metadata.push(format!("skill_instructions: {skill_instructions}"));
|
||||||
|
}
|
||||||
if metadata.is_empty() {
|
if metadata.is_empty() {
|
||||||
format!("{}\n", self.prompt)
|
format!("{}\n", self.prompt)
|
||||||
} else if self.prompt.is_empty() {
|
} else if self.prompt.is_empty() {
|
||||||
@@ -299,6 +315,14 @@ impl Role {
|
|||||||
self.continuation_prompt.as_deref()
|
self.continuation_prompt.as_deref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn inject_skill_instructions(&self) -> Option<bool> {
|
||||||
|
self.inject_skill_instructions
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn skill_instructions(&self) -> Option<&str> {
|
||||||
|
self.skill_instructions.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn skills_enabled(&self) -> Option<bool> {
|
pub fn skills_enabled(&self) -> Option<bool> {
|
||||||
self.skills_enabled
|
self.skills_enabled
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,10 @@ pub struct Session {
|
|||||||
inject_todo_instructions: Option<bool>,
|
inject_todo_instructions: Option<bool>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
continuation_prompt: Option<String>,
|
continuation_prompt: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
inject_skill_instructions: Option<bool>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
skill_instructions: Option<String>,
|
||||||
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
role_name: Option<String>,
|
role_name: Option<String>,
|
||||||
@@ -227,6 +231,12 @@ impl Session {
|
|||||||
if let Some(continuation_prompt) = self.continuation_prompt() {
|
if let Some(continuation_prompt) = self.continuation_prompt() {
|
||||||
data["continuation_prompt"] = continuation_prompt.into();
|
data["continuation_prompt"] = continuation_prompt.into();
|
||||||
}
|
}
|
||||||
|
if let Some(inject_skill_instructions) = self.inject_skill_instructions() {
|
||||||
|
data["inject_skill_instructions"] = inject_skill_instructions.into();
|
||||||
|
}
|
||||||
|
if let Some(skill_instructions) = self.skill_instructions() {
|
||||||
|
data["skill_instructions"] = skill_instructions.into();
|
||||||
|
}
|
||||||
let (tokens, percent) = self.tokens_usage();
|
let (tokens, percent) = self.tokens_usage();
|
||||||
data["total_tokens"] = tokens.into();
|
data["total_tokens"] = tokens.into();
|
||||||
if let Some(max_input_tokens) = self.model().max_input_tokens() {
|
if let Some(max_input_tokens) = self.model().max_input_tokens() {
|
||||||
@@ -305,6 +315,15 @@ impl Session {
|
|||||||
if let Some(continuation_prompt) = self.continuation_prompt() {
|
if let Some(continuation_prompt) = self.continuation_prompt() {
|
||||||
items.push(("continuation_prompt", continuation_prompt.to_string()));
|
items.push(("continuation_prompt", continuation_prompt.to_string()));
|
||||||
}
|
}
|
||||||
|
if let Some(inject_skill_instructions) = self.inject_skill_instructions() {
|
||||||
|
items.push((
|
||||||
|
"inject_skill_instructions",
|
||||||
|
inject_skill_instructions.to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if let Some(skill_instructions) = self.skill_instructions() {
|
||||||
|
items.push(("skill_instructions", skill_instructions.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(max_input_tokens) = self.model().max_input_tokens() {
|
if let Some(max_input_tokens) = self.model().max_input_tokens() {
|
||||||
items.push(("max_input_tokens", max_input_tokens.to_string()));
|
items.push(("max_input_tokens", max_input_tokens.to_string()));
|
||||||
@@ -446,6 +465,14 @@ impl Session {
|
|||||||
self.continuation_prompt.as_deref()
|
self.continuation_prompt.as_deref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn inject_skill_instructions(&self) -> Option<bool> {
|
||||||
|
self.inject_skill_instructions
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn skill_instructions(&self) -> Option<&str> {
|
||||||
|
self.skill_instructions.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_inject_todo_instructions(&mut self, value: Option<bool>) {
|
pub fn set_inject_todo_instructions(&mut self, value: Option<bool>) {
|
||||||
if self.inject_todo_instructions != value {
|
if self.inject_todo_instructions != value {
|
||||||
self.inject_todo_instructions = value;
|
self.inject_todo_instructions = value;
|
||||||
@@ -460,6 +487,20 @@ impl Session {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_inject_skill_instructions(&mut self, value: Option<bool>) {
|
||||||
|
if self.inject_skill_instructions != value {
|
||||||
|
self.inject_skill_instructions = value;
|
||||||
|
self.dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_skill_instructions(&mut self, value: Option<String>) {
|
||||||
|
if self.skill_instructions != value {
|
||||||
|
self.skill_instructions = value;
|
||||||
|
self.dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn needs_compression(&self, global_compression_threshold: usize) -> bool {
|
pub fn needs_compression(&self, global_compression_threshold: usize) -> bool {
|
||||||
if self.compressing {
|
if self.compressing {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
+243
-21
@@ -3,14 +3,16 @@ use super::app_config::AppConfig;
|
|||||||
use super::paths;
|
use super::paths;
|
||||||
use super::role::Role;
|
use super::role::Role;
|
||||||
use super::session::Session;
|
use super::session::Session;
|
||||||
|
use super::skill::Skill;
|
||||||
|
|
||||||
use anyhow::{Result, anyhow, bail};
|
use anyhow::{Result, anyhow, bail};
|
||||||
use std::collections::HashSet;
|
use std::collections::{BTreeSet, HashSet};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SkillPolicy {
|
pub struct SkillPolicy {
|
||||||
pub skills_enabled: bool,
|
pub skills_enabled: bool,
|
||||||
pub enabled: HashSet<String>,
|
pub enabled: HashSet<String>,
|
||||||
|
pub compatible_enabled: BTreeSet<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SkillPolicy {
|
impl SkillPolicy {
|
||||||
@@ -27,20 +29,27 @@ impl SkillPolicy {
|
|||||||
session,
|
session,
|
||||||
&paths::has_skill,
|
&paths::has_skill,
|
||||||
&paths::list_skills,
|
&paths::list_skills,
|
||||||
|
&|name, mcp_on| {
|
||||||
|
Skill::load(name)
|
||||||
|
.map(|s| s.is_compatible(mcp_on))
|
||||||
|
.unwrap_or(false)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn effective_with<F, G>(
|
fn effective_with<F, G, H>(
|
||||||
global: &AppConfig,
|
global: &AppConfig,
|
||||||
role: Option<&Role>,
|
role: Option<&Role>,
|
||||||
agent: Option<&Agent>,
|
agent: Option<&Agent>,
|
||||||
session: Option<&Session>,
|
session: Option<&Session>,
|
||||||
skill_exists: &F,
|
skill_exists: &F,
|
||||||
list_installed: &G,
|
list_installed: &G,
|
||||||
|
skill_is_compatible: &H,
|
||||||
) -> Result<Self>
|
) -> Result<Self>
|
||||||
where
|
where
|
||||||
F: Fn(&str) -> bool,
|
F: Fn(&str) -> bool,
|
||||||
G: Fn() -> Vec<String>,
|
G: Fn() -> Vec<String>,
|
||||||
|
H: Fn(&str, bool) -> bool,
|
||||||
{
|
{
|
||||||
let mut skills_enabled = global.skills_enabled;
|
let mut skills_enabled = global.skills_enabled;
|
||||||
if let Some(r) = role
|
if let Some(r) = role
|
||||||
@@ -104,9 +113,21 @@ impl SkillPolicy {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let compatible_enabled: BTreeSet<String> = if skills_enabled {
|
||||||
|
let mcp_on = global.mcp_server_support;
|
||||||
|
enabled
|
||||||
|
.iter()
|
||||||
|
.filter(|name| skill_is_compatible(name, mcp_on))
|
||||||
|
.cloned()
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
BTreeSet::new()
|
||||||
|
};
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
skills_enabled,
|
skills_enabled,
|
||||||
enabled,
|
enabled,
|
||||||
|
compatible_enabled,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,6 +149,10 @@ mod tests {
|
|||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn all_compatible(_: &str, _: bool) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn make_app_config(
|
fn make_app_config(
|
||||||
skills_enabled: bool,
|
skills_enabled: bool,
|
||||||
enabled: Option<&str>,
|
enabled: Option<&str>,
|
||||||
@@ -145,8 +170,15 @@ mod tests {
|
|||||||
fn defaults_yield_skills_enabled_with_empty_universe() {
|
fn defaults_yield_skills_enabled_with_empty_universe() {
|
||||||
let global = AppConfig::default();
|
let global = AppConfig::default();
|
||||||
|
|
||||||
let policy =
|
let policy = SkillPolicy::effective_with(
|
||||||
SkillPolicy::effective_with(&global, None, None, None, &always_true, &empty_installed)
|
&global,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
&always_true,
|
||||||
|
&empty_installed,
|
||||||
|
&all_compatible,
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert!(policy.skills_enabled);
|
assert!(policy.skills_enabled);
|
||||||
@@ -158,8 +190,15 @@ mod tests {
|
|||||||
let global = AppConfig::default();
|
let global = AppConfig::default();
|
||||||
let installed = || vec!["alpha".to_string(), "beta".to_string()];
|
let installed = || vec!["alpha".to_string(), "beta".to_string()];
|
||||||
|
|
||||||
let policy =
|
let policy = SkillPolicy::effective_with(
|
||||||
SkillPolicy::effective_with(&global, None, None, None, &always_true, &installed)
|
&global,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
&always_true,
|
||||||
|
&installed,
|
||||||
|
&all_compatible,
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(policy.enabled.len(), 2);
|
assert_eq!(policy.enabled.len(), 2);
|
||||||
@@ -171,8 +210,15 @@ mod tests {
|
|||||||
fn falls_back_to_visible_when_visible_set_but_no_enabled() {
|
fn falls_back_to_visible_when_visible_set_but_no_enabled() {
|
||||||
let global = make_app_config(true, None, Some(&["alpha", "beta"]));
|
let global = make_app_config(true, None, Some(&["alpha", "beta"]));
|
||||||
|
|
||||||
let policy =
|
let policy = SkillPolicy::effective_with(
|
||||||
SkillPolicy::effective_with(&global, None, None, None, &always_true, &empty_installed)
|
&global,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
&always_true,
|
||||||
|
&empty_installed,
|
||||||
|
&all_compatible,
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(policy.enabled.len(), 2);
|
assert_eq!(policy.enabled.len(), 2);
|
||||||
@@ -184,8 +230,15 @@ mod tests {
|
|||||||
fn global_enabled_skills_is_effective_when_no_other_levels() {
|
fn global_enabled_skills_is_effective_when_no_other_levels() {
|
||||||
let global = make_app_config(true, Some("alpha,beta"), Some(&["alpha", "beta", "gamma"]));
|
let global = make_app_config(true, Some("alpha,beta"), Some(&["alpha", "beta", "gamma"]));
|
||||||
|
|
||||||
let policy =
|
let policy = SkillPolicy::effective_with(
|
||||||
SkillPolicy::effective_with(&global, None, None, None, &always_true, &empty_installed)
|
&global,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
&always_true,
|
||||||
|
&empty_installed,
|
||||||
|
&all_compatible,
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert!(policy.enabled.contains("alpha"));
|
assert!(policy.enabled.contains("alpha"));
|
||||||
@@ -205,6 +258,7 @@ mod tests {
|
|||||||
None,
|
None,
|
||||||
&always_true,
|
&always_true,
|
||||||
&empty_installed,
|
&empty_installed,
|
||||||
|
&all_compatible,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -224,6 +278,7 @@ mod tests {
|
|||||||
None,
|
None,
|
||||||
&always_true,
|
&always_true,
|
||||||
&empty_installed,
|
&empty_installed,
|
||||||
|
&all_compatible,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -237,9 +292,15 @@ mod tests {
|
|||||||
..AppConfig::default()
|
..AppConfig::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let policy = SkillPolicy::effective_with(&global, None, None, None, &always_true, &|| {
|
let policy = SkillPolicy::effective_with(
|
||||||
vec!["alpha".to_string()]
|
&global,
|
||||||
})
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
&always_true,
|
||||||
|
&|| vec!["alpha".to_string()],
|
||||||
|
&all_compatible,
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert!(!policy.allows("alpha"));
|
assert!(!policy.allows("alpha"));
|
||||||
@@ -249,8 +310,15 @@ mod tests {
|
|||||||
fn allows_returns_true_when_skill_in_enabled_set() {
|
fn allows_returns_true_when_skill_in_enabled_set() {
|
||||||
let global = make_app_config(true, Some("alpha"), None);
|
let global = make_app_config(true, Some("alpha"), None);
|
||||||
|
|
||||||
let policy =
|
let policy = SkillPolicy::effective_with(
|
||||||
SkillPolicy::effective_with(&global, None, None, None, &always_true, &empty_installed)
|
&global,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
&always_true,
|
||||||
|
&empty_installed,
|
||||||
|
&all_compatible,
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert!(policy.allows("alpha"));
|
assert!(policy.allows("alpha"));
|
||||||
@@ -261,8 +329,15 @@ mod tests {
|
|||||||
fn validation_rejects_uninstalled_skill_reference() {
|
fn validation_rejects_uninstalled_skill_reference() {
|
||||||
let global = make_app_config(true, Some("ghost"), None);
|
let global = make_app_config(true, Some("ghost"), None);
|
||||||
|
|
||||||
let err =
|
let err = SkillPolicy::effective_with(
|
||||||
SkillPolicy::effective_with(&global, None, None, None, &|_| false, &empty_installed)
|
&global,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
&|_| false,
|
||||||
|
&empty_installed,
|
||||||
|
&all_compatible,
|
||||||
|
)
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
|
|
||||||
assert!(err.to_string().contains("not installed"));
|
assert!(err.to_string().contains("not installed"));
|
||||||
@@ -273,8 +348,15 @@ mod tests {
|
|||||||
fn validation_rejects_skill_not_in_visible_set() {
|
fn validation_rejects_skill_not_in_visible_set() {
|
||||||
let global = make_app_config(true, Some("beta"), Some(&["alpha"]));
|
let global = make_app_config(true, Some("beta"), Some(&["alpha"]));
|
||||||
|
|
||||||
let err =
|
let err = SkillPolicy::effective_with(
|
||||||
SkillPolicy::effective_with(&global, None, None, None, &always_true, &empty_installed)
|
&global,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
&always_true,
|
||||||
|
&empty_installed,
|
||||||
|
&all_compatible,
|
||||||
|
)
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
@@ -288,8 +370,15 @@ mod tests {
|
|||||||
fn validation_skipped_when_no_explicit_enabled_skills() {
|
fn validation_skipped_when_no_explicit_enabled_skills() {
|
||||||
let global = make_app_config(true, None, None);
|
let global = make_app_config(true, None, None);
|
||||||
|
|
||||||
let policy =
|
let policy = SkillPolicy::effective_with(
|
||||||
SkillPolicy::effective_with(&global, None, None, None, &|_| false, &empty_installed)
|
&global,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
&|_| false,
|
||||||
|
&empty_installed,
|
||||||
|
&all_compatible,
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert!(policy.enabled.is_empty());
|
assert!(policy.enabled.is_empty());
|
||||||
@@ -307,9 +396,142 @@ mod tests {
|
|||||||
None,
|
None,
|
||||||
&always_true,
|
&always_true,
|
||||||
&empty_installed,
|
&empty_installed,
|
||||||
|
&all_compatible,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert!(policy.enabled.is_empty());
|
assert!(policy.enabled.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn compatible_enabled_is_empty_when_skills_disabled() {
|
||||||
|
let global = AppConfig {
|
||||||
|
skills_enabled: false,
|
||||||
|
enabled_skills: Some(vec!["alpha".into()]),
|
||||||
|
visible_skills: Some(vec!["alpha".into()]),
|
||||||
|
..AppConfig::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let policy = SkillPolicy::effective_with(
|
||||||
|
&global,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
&always_true,
|
||||||
|
&empty_installed,
|
||||||
|
&all_compatible,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(!policy.skills_enabled);
|
||||||
|
assert!(policy.compatible_enabled.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn compatible_enabled_short_circuits_callback_when_skills_disabled() {
|
||||||
|
use std::cell::Cell;
|
||||||
|
let global = AppConfig {
|
||||||
|
skills_enabled: false,
|
||||||
|
enabled_skills: Some(vec!["alpha".into()]),
|
||||||
|
visible_skills: Some(vec!["alpha".into()]),
|
||||||
|
..AppConfig::default()
|
||||||
|
};
|
||||||
|
let invoked = Cell::new(0u32);
|
||||||
|
let counting = |_: &str, _: bool| {
|
||||||
|
invoked.set(invoked.get() + 1);
|
||||||
|
true
|
||||||
|
};
|
||||||
|
|
||||||
|
SkillPolicy::effective_with(
|
||||||
|
&global,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
&always_true,
|
||||||
|
&empty_installed,
|
||||||
|
&counting,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
invoked.get(),
|
||||||
|
0,
|
||||||
|
"skill_is_compatible callback must not run when skills are disabled"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn compatible_enabled_includes_all_when_callback_passes() {
|
||||||
|
let global = make_app_config(true, Some("alpha,beta"), Some(&["alpha", "beta"]));
|
||||||
|
|
||||||
|
let policy = SkillPolicy::effective_with(
|
||||||
|
&global,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
&always_true,
|
||||||
|
&empty_installed,
|
||||||
|
&all_compatible,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(policy.compatible_enabled.len(), 2);
|
||||||
|
assert!(policy.compatible_enabled.contains("alpha"));
|
||||||
|
assert!(policy.compatible_enabled.contains("beta"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn compatible_enabled_excludes_incompatible_skills() {
|
||||||
|
let global = make_app_config(true, Some("alpha,beta"), Some(&["alpha", "beta"]));
|
||||||
|
let only_alpha_compat = |name: &str, _: bool| name == "alpha";
|
||||||
|
|
||||||
|
let policy = SkillPolicy::effective_with(
|
||||||
|
&global,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
&always_true,
|
||||||
|
&empty_installed,
|
||||||
|
&only_alpha_compat,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(policy.compatible_enabled.contains("alpha"));
|
||||||
|
assert!(!policy.compatible_enabled.contains("beta"));
|
||||||
|
assert_eq!(policy.compatible_enabled.len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn compatible_enabled_passes_mcp_flag_to_callback() {
|
||||||
|
use std::cell::Cell;
|
||||||
|
let global = AppConfig {
|
||||||
|
skills_enabled: true,
|
||||||
|
mcp_server_support: false,
|
||||||
|
enabled_skills: Some(vec!["alpha".into()]),
|
||||||
|
visible_skills: Some(vec!["alpha".into()]),
|
||||||
|
..AppConfig::default()
|
||||||
|
};
|
||||||
|
let observed_mcp = Cell::new(None::<bool>);
|
||||||
|
let capture = |_: &str, mcp_on: bool| {
|
||||||
|
observed_mcp.set(Some(mcp_on));
|
||||||
|
true
|
||||||
|
};
|
||||||
|
|
||||||
|
SkillPolicy::effective_with(
|
||||||
|
&global,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
&always_true,
|
||||||
|
&empty_installed,
|
||||||
|
&capture,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
observed_mcp.get(),
|
||||||
|
Some(false),
|
||||||
|
"callback must receive mcp_server_support flag from AppConfig"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ impl SkillRegistry {
|
|||||||
let policy = SkillPolicy {
|
let policy = SkillPolicy {
|
||||||
skills_enabled: true,
|
skills_enabled: true,
|
||||||
enabled: self.loaded.keys().cloned().collect(),
|
enabled: self.loaded.keys().cloned().collect(),
|
||||||
|
compatible_enabled: self.loaded.keys().cloned().collect(),
|
||||||
};
|
};
|
||||||
self.effective_role(base, &policy)
|
self.effective_role(base, &policy)
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-15
@@ -14,9 +14,11 @@ pub fn skill_function_declarations() -> Vec<FunctionDeclaration> {
|
|||||||
FunctionDeclaration {
|
FunctionDeclaration {
|
||||||
name: format!("{SKILL_FUNCTION_PREFIX}list"),
|
name: format!("{SKILL_FUNCTION_PREFIX}list"),
|
||||||
description:
|
description:
|
||||||
"List skills available in this context. Returns each skill's name, description, \
|
"List skills available in this context. Call this early in any non-trivial task to \
|
||||||
what tools and MCP servers it grants on load, and whether it is currently loaded. \
|
discover specialized skills that may apply to the work before deciding on an \
|
||||||
Call this to discover skills before using skill__load."
|
approach. Returns each skill's name, description, what tools and MCP servers it \
|
||||||
|
grants on load, and whether it is currently loaded. Pair with `skill__load` to \
|
||||||
|
activate the skills you choose."
|
||||||
.to_string(),
|
.to_string(),
|
||||||
parameters: JsonSchema {
|
parameters: JsonSchema {
|
||||||
type_value: Some("object".to_string()),
|
type_value: Some("object".to_string()),
|
||||||
@@ -28,9 +30,10 @@ pub fn skill_function_declarations() -> Vec<FunctionDeclaration> {
|
|||||||
FunctionDeclaration {
|
FunctionDeclaration {
|
||||||
name: format!("{SKILL_FUNCTION_PREFIX}load"),
|
name: format!("{SKILL_FUNCTION_PREFIX}load"),
|
||||||
description:
|
description:
|
||||||
"Load a skill module into the current context. The skill's instructions and any \
|
"Load a skill module into the current context after confirming via `skill__list` \
|
||||||
tools or MCP servers it grants become active for subsequent turns. Call \
|
that it applies to the task at hand. The skill's instructions and any tools or \
|
||||||
skill__unload when the skill's work is complete to keep the context lean."
|
MCP servers it grants become active for subsequent turns. Call `skill__unload` \
|
||||||
|
when the skill's work is complete to keep the context lean."
|
||||||
.to_string(),
|
.to_string(),
|
||||||
parameters: JsonSchema {
|
parameters: JsonSchema {
|
||||||
type_value: Some("object".to_string()),
|
type_value: Some("object".to_string()),
|
||||||
@@ -102,8 +105,6 @@ pub async fn handle_skill_tool(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_list(ctx: &RequestContext, policy: &SkillPolicy) -> Result<Value> {
|
fn handle_list(ctx: &RequestContext, policy: &SkillPolicy) -> Result<Value> {
|
||||||
let mcp_on = ctx.app.config.mcp_server_support;
|
|
||||||
|
|
||||||
let visible_names: Vec<String> = match ctx.app.config.visible_skills.as_deref() {
|
let visible_names: Vec<String> = match ctx.app.config.visible_skills.as_deref() {
|
||||||
Some(list) => list.to_vec(),
|
Some(list) => list.to_vec(),
|
||||||
None => paths::list_skills(),
|
None => paths::list_skills(),
|
||||||
@@ -111,7 +112,7 @@ fn handle_list(ctx: &RequestContext, policy: &SkillPolicy) -> Result<Value> {
|
|||||||
|
|
||||||
let mut entries = Vec::new();
|
let mut entries = Vec::new();
|
||||||
for name in visible_names {
|
for name in visible_names {
|
||||||
if !policy.allows(&name) {
|
if !policy.compatible_enabled.contains(&name) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,12 +123,6 @@ fn handle_list(ctx: &RequestContext, policy: &SkillPolicy) -> Result<Value> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if !skill.is_compatible(mcp_on) {
|
|
||||||
warn!(
|
|
||||||
"Skill '{name}' filtered from list: declares MCP servers but MCP support is disabled"
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
entries.push(json!({
|
entries.push(json!({
|
||||||
"name": skill.name(),
|
"name": skill.name(),
|
||||||
|
|||||||
+31
-1
@@ -2,7 +2,10 @@ use super::state::StateManager;
|
|||||||
use super::structured;
|
use super::structured;
|
||||||
use super::types::LlmNode;
|
use super::types::LlmNode;
|
||||||
use crate::client::{Model, ModelType, call_chat_completions};
|
use crate::client::{Model, ModelType, call_chat_completions};
|
||||||
use crate::config::{Input, RequestContext, Role, RoleLike, SkillPolicy};
|
use crate::config::prompts::DEFAULT_SKILL_INSTRUCTIONS;
|
||||||
|
use crate::config::{
|
||||||
|
Input, RequestContext, Role, RoleLike, SkillPolicy, should_inject_skill_instructions,
|
||||||
|
};
|
||||||
use crate::function::skill::skill_function_declarations;
|
use crate::function::skill::skill_function_declarations;
|
||||||
use crate::utils::create_abort_signal;
|
use crate::utils::create_abort_signal;
|
||||||
use anyhow::{Context, Error, Result, anyhow, bail};
|
use anyhow::{Context, Error, Result, anyhow, bail};
|
||||||
@@ -139,6 +142,31 @@ async fn run(
|
|||||||
role.set_enabled_tools(Some(tools));
|
role.set_enabled_tools(Some(tools));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if should_inject_skill_instructions(&parent_ctx.app.config, &policy) {
|
||||||
|
let app = &parent_ctx.app.config;
|
||||||
|
let agent = parent_ctx.agent.as_ref();
|
||||||
|
let inject = node
|
||||||
|
.inject_skill_instructions
|
||||||
|
.or_else(|| agent.map(|a| a.inject_skill_instructions()))
|
||||||
|
.unwrap_or(app.inject_skill_instructions);
|
||||||
|
|
||||||
|
if inject {
|
||||||
|
let instructions = node
|
||||||
|
.skill_instructions
|
||||||
|
.clone()
|
||||||
|
.or_else(|| agent.and_then(|a| a.skill_instructions_value()))
|
||||||
|
.or_else(|| app.skill_instructions.clone());
|
||||||
|
let separator = if role.is_empty_prompt() { "" } else { "\n\n" };
|
||||||
|
|
||||||
|
role.append_to_prompt(separator);
|
||||||
|
role.append_to_prompt(
|
||||||
|
instructions
|
||||||
|
.as_deref()
|
||||||
|
.unwrap_or(DEFAULT_SKILL_INSTRUCTIONS),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let composed_role = parent_ctx.skill_registry.effective_role(&role, &policy);
|
let composed_role = parent_ctx.skill_registry.effective_role(&role, &policy);
|
||||||
|
|
||||||
let saved_role = parent_ctx.role.clone();
|
let saved_role = parent_ctx.role.clone();
|
||||||
@@ -456,6 +484,8 @@ mod tests {
|
|||||||
timeout: None,
|
timeout: None,
|
||||||
skills_enabled: None,
|
skills_enabled: None,
|
||||||
enabled_skills: None,
|
enabled_skills: None,
|
||||||
|
inject_skill_instructions: None,
|
||||||
|
skill_instructions: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,12 @@ pub struct Graph {
|
|||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub enabled_skills: Option<Vec<String>>,
|
pub enabled_skills: Option<Vec<String>>,
|
||||||
|
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub inject_skill_instructions: Option<bool>,
|
||||||
|
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub skill_instructions: Option<String>,
|
||||||
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub conversation_starters: Vec<String>,
|
pub conversation_starters: Vec<String>,
|
||||||
|
|
||||||
@@ -305,6 +311,12 @@ pub struct LlmNode {
|
|||||||
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub enabled_skills: Option<Vec<String>>,
|
pub enabled_skills: Option<Vec<String>>,
|
||||||
|
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub inject_skill_instructions: Option<bool>,
|
||||||
|
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub skill_instructions: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_llm_max_attempts() -> u32 {
|
fn default_llm_max_attempts() -> u32 {
|
||||||
|
|||||||
@@ -950,6 +950,8 @@ mod tests {
|
|||||||
mcp_servers: Vec::new(),
|
mcp_servers: Vec::new(),
|
||||||
skills_enabled: None,
|
skills_enabled: None,
|
||||||
enabled_skills: None,
|
enabled_skills: None,
|
||||||
|
inject_skill_instructions: None,
|
||||||
|
skill_instructions: None,
|
||||||
conversation_starters: Vec::new(),
|
conversation_starters: Vec::new(),
|
||||||
variables: Vec::new(),
|
variables: Vec::new(),
|
||||||
settings: GraphSettings::default(),
|
settings: GraphSettings::default(),
|
||||||
@@ -1051,6 +1053,8 @@ mod tests {
|
|||||||
timeout: None,
|
timeout: None,
|
||||||
skills_enabled: None,
|
skills_enabled: None,
|
||||||
enabled_skills: None,
|
enabled_skills: None,
|
||||||
|
inject_skill_instructions: None,
|
||||||
|
skill_instructions: None,
|
||||||
}),
|
}),
|
||||||
next: next.map(NextTargets::from),
|
next: next.map(NextTargets::from),
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user