|
60 | 60 | ([all-tools tool args db config agent-name] |
61 | 61 | (approval all-tools tool args db config agent-name nil)) |
62 | 62 | ([all-tools tool args db config agent-name {:keys [trust]}] |
63 | | - (let [{:keys [server name require-approval-fn]} tool |
64 | | - remember-to-approve? (get-in db [:tool-calls name :remember-to-approve?]) |
| 63 | + (let [{:keys [server name require-approval-fn approval-keys-fn]} tool |
| 64 | + remembered? (if approval-keys-fn |
| 65 | + ;; Granular remember: every derived key (e.g. "git checkout") |
| 66 | + ;; must have been remembered, and the command must be fully |
| 67 | + ;; understood (:complete?), otherwise still ask. |
| 68 | + (let [{keys' :keys complete? :complete?} (approval-keys-fn args) |
| 69 | + remembered-keys (get-in db [:tool-calls name :remembered-command-keys] #{})] |
| 70 | + (boolean (and complete? |
| 71 | + (seq keys') |
| 72 | + (every? remembered-keys keys')))) |
| 73 | + (boolean (get-in db [:tool-calls name :remember-to-approve?]))) |
65 | 74 | native-tools (filter #(= :native (:origin %)) all-tools) |
66 | 75 | {:keys [allow ask deny byDefault]} (merge (get-in config [:toolCall :approval]) |
67 | 76 | (get-in config [:agent agent-name :toolCall :approval])) |
68 | 77 | result (cond |
69 | | - remember-to-approve? |
| 78 | + (some #(approval-matches? % (:name server) name args native-tools) deny) |
| 79 | + :deny |
| 80 | + |
| 81 | + remembered? |
70 | 82 | :allow |
71 | 83 |
|
72 | 84 | (and require-approval-fn (require-approval-fn args {:db db})) |
73 | 85 | :ask |
74 | 86 |
|
75 | | - (some #(approval-matches? % (:name server) name args native-tools) deny) |
76 | | - :deny |
77 | | - |
78 | 87 | (some #(approval-matches? % (:name server) name args native-tools) ask) |
79 | 88 | :ask |
80 | 89 |
|
|
130 | 139 | x)) |
131 | 140 | m)) |
132 | 141 |
|
| 142 | +(defn ^:private static-native-definitions |
| 143 | + "Native tool definitions that don't depend on chat/db/config." |
| 144 | + [] |
| 145 | + (merge {} |
| 146 | + f.tools.filesystem/definitions |
| 147 | + f.tools.shell/definitions |
| 148 | + f.tools.git/definitions |
| 149 | + f.tools.editor/definitions |
| 150 | + f.tools.chat/definitions |
| 151 | + f.tools.skill/definitions |
| 152 | + f.tools.task/definitions |
| 153 | + f.tools.background/definitions |
| 154 | + f.tools.ask-user/definitions)) |
| 155 | + |
| 156 | +(defn tool-approval-keys |
| 157 | + "Returns {:keys #{...} :complete? bool} when the native tool `tool-name` |
| 158 | + defines granular approval keys for these arguments, else nil." |
| 159 | + [tool-name arguments] |
| 160 | + (when-let [approval-keys-fn (get-in (static-native-definitions) [tool-name :approval-keys-fn])] |
| 161 | + (approval-keys-fn arguments))) |
| 162 | + |
133 | 163 | (defn ^:private native-definitions |
134 | 164 | [chat-id agent-name db config] |
135 | 165 | (into |
|
142 | 172 | :readFileMaxLines (get-in config [:toolCall :readFile :maxLines]) |
143 | 173 | :fullModel (get-in db [:chats chat-id :model]) |
144 | 174 | :variant (get-in db [:chats chat-id :variant])}))])) |
145 | | - (merge {} |
146 | | - f.tools.filesystem/definitions |
147 | | - f.tools.shell/definitions |
148 | | - f.tools.git/definitions |
149 | | - f.tools.editor/definitions |
150 | | - f.tools.chat/definitions |
151 | | - f.tools.skill/definitions |
152 | | - f.tools.task/definitions |
153 | | - f.tools.background/definitions |
154 | | - f.tools.ask-user/definitions |
| 175 | + (merge (static-native-definitions) |
155 | 176 | (f.tools.agent/definitions config db) |
156 | 177 | (f.tools.custom/definitions config) |
157 | 178 | (f.tools.fetch-rule/definitions config db chat-id agent-name)))) |
|
0 commit comments