@capybara-hq/kernel 0.1.0-rc.2 → 0.1.0-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/agent-lookup.js +10 -2
- package/dist/agents/agents.service.js +19 -6
- package/dist/agents/definition.d.ts +31 -8
- package/dist/agents/definition.js +193 -17
- package/dist/agents/templates.js +19 -4
- package/dist/catalog/catalog-content.js +4 -1
- package/dist/catalog/claude/agents.js +13 -10
- package/dist/catalog/marketplaces.service.d.ts +1 -1
- package/dist/channels/cards.d.ts +8 -2
- package/dist/channels/cards.js +16 -8
- package/dist/config/schema.js +2 -2
- package/dist/conversations/artifacts.d.ts +1 -1
- package/dist/conversations/artifacts.js +1 -1
- package/dist/conversations/event-log.d.ts +11 -0
- package/dist/conversations/event-log.js +19 -0
- package/dist/conversations/events.d.ts +23 -3
- package/dist/conversations/events.js +26 -14
- package/dist/db/kernel-schema.d.ts +2 -2
- package/dist/evals/recorded-tools.d.ts +27 -1
- package/dist/evals/recorded-tools.js +85 -10
- package/dist/evals/run-replay.d.ts +5 -0
- package/dist/evals/run-replay.js +19 -5
- package/dist/evals/trajectory.d.ts +2 -2
- package/dist/identity/settings.js +1 -1
- package/dist/lifecycle/kernel-lifecycle.js +5 -0
- package/dist/orgs/settings.service.d.ts +2 -2
- package/dist/orgs/settings.service.js +2 -2
- package/dist/runtime/context/build.d.ts +6 -6
- package/dist/runtime/context/build.js +18 -8
- package/dist/runtime/context/claude-tools.d.ts +2 -1
- package/dist/runtime/context/claude-tools.js +9 -10
- package/dist/runtime/context/legacy-text.d.ts +22 -0
- package/dist/runtime/context/legacy-text.js +37 -0
- package/dist/runtime/context/skills.d.ts +29 -11
- package/dist/runtime/context/skills.js +37 -30
- package/dist/runtime/loop.d.ts +1 -1
- package/dist/runtime/model-call.js +1 -1
- package/dist/runtime/run-finish.d.ts +1 -1
- package/dist/runtime/run-queue.d.ts +3 -3
- package/dist/runtime/run-queue.js +2 -2
- package/dist/runtime/run-worker.d.ts +2 -2
- package/dist/runtime/run-worker.js +4 -4
- package/dist/runtime/subagents/definition.d.ts +1 -6
- package/dist/runtime/subagents/definition.js +11 -12
- package/dist/runtime/subagents/dispatch.d.ts +2 -2
- package/dist/runtime/subagents/dispatch.js +2 -2
- package/dist/runtime/subagents/org-agents.js +2 -1
- package/dist/runtime/subagents/roster.d.ts +1 -1
- package/dist/runtime/subagents/roster.js +1 -1
- package/dist/runtime/subagents/skill-fork.d.ts +2 -2
- package/dist/runtime/subagents/skill-fork.js +2 -2
- package/dist/runtime/subagents/subagents.service.d.ts +3 -3
- package/dist/runtime/subagents/subagents.service.js +3 -3
- package/dist/runtime/waits.d.ts +5 -5
- package/dist/runtime/waits.js +5 -5
- package/dist/skills/catalog.d.ts +4 -4
- package/dist/skills/catalog.js +4 -4
- package/dist/skills/changes.service.d.ts +2 -2
- package/dist/skills/changes.service.js +5 -4
- package/dist/skills/invocation-keys.d.ts +1 -1
- package/dist/skills/invocation-keys.js +1 -1
- package/dist/skills/invoke.d.ts +1 -1
- package/dist/skills/invoke.js +5 -4
- package/dist/tools/approvals.service.d.ts +6 -0
- package/dist/tools/approvals.service.js +19 -1
- package/dist/tools/builtin-names.d.ts +73 -0
- package/dist/tools/builtin-names.js +116 -0
- package/dist/tools/builtins/agent.d.ts +7 -7
- package/dist/tools/builtins/agent.js +7 -11
- package/dist/tools/builtins/ask-user.d.ts +1 -1
- package/dist/tools/builtins/ask-user.js +2 -2
- package/dist/tools/builtins/builtin-tools.d.ts +2 -2
- package/dist/tools/builtins/builtin-tools.js +2 -2
- package/dist/tools/builtins/read-tool-output.d.ts +1 -1
- package/dist/tools/builtins/read-tool-output.js +2 -2
- package/dist/tools/builtins/sandbox/bash.d.ts +5 -5
- package/dist/tools/builtins/sandbox/bash.js +31 -28
- package/dist/tools/builtins/sandbox/common.d.ts +3 -3
- package/dist/tools/builtins/sandbox/common.js +2 -2
- package/dist/tools/builtins/sandbox/deliver.d.ts +1 -1
- package/dist/tools/builtins/sandbox/deliver.js +11 -11
- package/dist/tools/builtins/sandbox/edit.d.ts +1 -1
- package/dist/tools/builtins/sandbox/edit.js +41 -30
- package/dist/tools/builtins/sandbox/file-state.d.ts +34 -0
- package/dist/tools/builtins/sandbox/file-state.js +34 -0
- package/dist/tools/builtins/sandbox/glob-match.d.ts +1 -1
- package/dist/tools/builtins/sandbox/glob-match.js +1 -1
- package/dist/tools/builtins/sandbox/glob.d.ts +1 -1
- package/dist/tools/builtins/sandbox/glob.js +4 -4
- package/dist/tools/builtins/sandbox/grep.d.ts +7 -4
- package/dist/tools/builtins/sandbox/grep.js +147 -30
- package/dist/tools/builtins/sandbox/index.d.ts +1 -1
- package/dist/tools/builtins/sandbox/index.js +1 -1
- package/dist/tools/builtins/sandbox/read.d.ts +2 -2
- package/dist/tools/builtins/sandbox/read.js +21 -14
- package/dist/tools/builtins/sandbox/write.d.ts +1 -1
- package/dist/tools/builtins/sandbox/write.js +37 -33
- package/dist/tools/builtins/skill-load.d.ts +3 -3
- package/dist/tools/builtins/skill-load.js +32 -16
- package/dist/tools/builtins/skill-write.d.ts +4 -4
- package/dist/tools/builtins/skill-write.js +10 -10
- package/dist/tools/builtins/tool-search.d.ts +13 -9
- package/dist/tools/builtins/tool-search.js +25 -14
- package/dist/tools/connectors.service.js +4 -4
- package/dist/tools/display-names.d.ts +9 -0
- package/dist/tools/display-names.js +24 -0
- package/dist/tools/drift.js +5 -5
- package/dist/tools/elicitation.js +1 -1
- package/dist/tools/info.d.ts +20 -4
- package/dist/tools/info.js +55 -32
- package/dist/tools/legacy-data.d.ts +34 -0
- package/dist/tools/legacy-data.js +76 -0
- package/dist/tools/legacy-keys.d.ts +51 -0
- package/dist/tools/legacy-keys.js +115 -0
- package/dist/tools/naming.d.ts +1 -5
- package/dist/tools/naming.js +1 -7
- package/dist/tools/outputs.js +1 -1
- package/dist/tools/pipeline.d.ts +13 -7
- package/dist/tools/pipeline.js +97 -39
- package/dist/tools/policy.d.ts +1 -14
- package/dist/tools/policy.js +13 -19
- package/dist/tools/questions.controller.d.ts +1 -1
- package/dist/tools/questions.controller.js +1 -1
- package/dist/tools/questions.service.d.ts +1 -1
- package/dist/tools/registry.d.ts +16 -21
- package/dist/tools/registry.js +29 -37
- package/dist/tools/resources.d.ts +1 -1
- package/dist/tools/resources.js +1 -1
- package/dist/tools/tools.module.js +1 -1
- package/package.json +2 -2
- package/src/migrations/0063_tool_keys_claude_code.sql +220 -0
- package/dist/tools/builtins/sandbox/names.d.ts +0 -7
- package/dist/tools/builtins/sandbox/names.js +0 -20
|
@@ -11,7 +11,8 @@ import { Inject, Injectable, Module } from "@nestjs/common";
|
|
|
11
11
|
import { sql } from "kysely";
|
|
12
12
|
import { ApiError } from "../errors.js";
|
|
13
13
|
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
14
|
-
import {
|
|
14
|
+
import { loadLegacyScope } from "../tools/legacy-data.js";
|
|
15
|
+
import { needsLegacyScope, normalizeStoredDefinition } from "./definition.js";
|
|
15
16
|
export const AGENT_VISIBILITIES = ["private", "org", "members"];
|
|
16
17
|
const notFound = () => new ApiError("agent.not_found", "Agent not found");
|
|
17
18
|
/**
|
|
@@ -142,6 +143,13 @@ let AgentLookup = class AgentLookup {
|
|
|
142
143
|
.orderBy("account_id")
|
|
143
144
|
.execute();
|
|
144
145
|
const byId = new Map(rows.map((r) => [r.id, r]));
|
|
146
|
+
// rc `<x>__<tool>` keys read with their org's scope, loaded once per org that needs it
|
|
147
|
+
const scopes = new Map();
|
|
148
|
+
for (const r of rows) {
|
|
149
|
+
if (!scopes.has(r.org_id) && needsLegacyScope(r.definition)) {
|
|
150
|
+
scopes.set(r.org_id, await loadLegacyScope(this.db.db, r.org_id));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
145
153
|
return ids.flatMap((id) => {
|
|
146
154
|
const r = byId.get(id);
|
|
147
155
|
if (!r)
|
|
@@ -153,7 +161,7 @@ let AgentLookup = class AgentLookup {
|
|
|
153
161
|
ownerAccountId: r.owner_account_id,
|
|
154
162
|
visibility: r.visibility,
|
|
155
163
|
currentVersion: r.current_version,
|
|
156
|
-
definition: normalizeStoredDefinition(r.definition),
|
|
164
|
+
definition: normalizeStoredDefinition(r.definition, scopes.get(r.org_id)),
|
|
157
165
|
memberIds: r.visibility === "members"
|
|
158
166
|
? memberRows.filter((m) => m.agent_id === id).map((m) => m.account_id)
|
|
159
167
|
: null,
|
|
@@ -24,6 +24,7 @@ import { ProviderRegistry } from "../runtime/providers.js";
|
|
|
24
24
|
import { SandboxJobs } from "../sandbox/jobs.js";
|
|
25
25
|
import { SkillChangesService } from "../skills/changes.service.js";
|
|
26
26
|
import { assertOrgSkills, assertPinnedSkills } from "../skills/skills.service.js";
|
|
27
|
+
import { legacyKeySaveText } from "../tools/legacy-keys.js";
|
|
27
28
|
import { ToolRegistry } from "../tools/registry.js";
|
|
28
29
|
import { AgentLookup, isAgentVisibleTo, visibleTo, } from "./agent-lookup.js";
|
|
29
30
|
import { normalizeStoredDefinition, paramIssues, SUBAGENT_NAME_RE, SUBAGENT_ROSTER_MAX, } from "./definition.js";
|
|
@@ -67,8 +68,13 @@ export async function assertSubagents(t, a) {
|
|
|
67
68
|
if (sub === undefined)
|
|
68
69
|
return;
|
|
69
70
|
const details = [];
|
|
70
|
-
const add = (reason, path, value) => {
|
|
71
|
-
details.push({
|
|
71
|
+
const add = (reason, path, value, message) => {
|
|
72
|
+
details.push({
|
|
73
|
+
reason,
|
|
74
|
+
path,
|
|
75
|
+
...(value !== undefined && { value }),
|
|
76
|
+
...(message !== undefined && { message }),
|
|
77
|
+
});
|
|
72
78
|
};
|
|
73
79
|
const types = new Set(sub.general === false ? [] : ["general-purpose"]);
|
|
74
80
|
const claim = (type, path) => {
|
|
@@ -123,8 +129,11 @@ export async function assertSubagents(t, a) {
|
|
|
123
129
|
const base = `subagents.inline.${i}`;
|
|
124
130
|
name(x.name, `${base}.name`);
|
|
125
131
|
const tool = (key, path) => {
|
|
126
|
-
if (
|
|
127
|
-
|
|
132
|
+
if (a.toolKeys.has(key))
|
|
133
|
+
return;
|
|
134
|
+
// an rc key names its current key(s) (tool naming spec §8.3)
|
|
135
|
+
const renamed = legacyKeySaveText(key, a.toolKeys);
|
|
136
|
+
add("tool_not_selected", path, key, renamed ?? undefined);
|
|
128
137
|
};
|
|
129
138
|
for (const [j, key] of (x.tools ?? []).entries())
|
|
130
139
|
tool(key, `${base}.tools.${j}`);
|
|
@@ -167,7 +176,9 @@ export async function assertSubagents(t, a) {
|
|
|
167
176
|
if (count > SUBAGENT_ROSTER_MAX)
|
|
168
177
|
add("too_many", "subagents");
|
|
169
178
|
if (details.length > 0) {
|
|
170
|
-
throw new ApiError("agent.subagents_invalid", `Invalid sub-agents: ${details
|
|
179
|
+
throw new ApiError("agent.subagents_invalid", `Invalid sub-agents: ${details
|
|
180
|
+
.map((d) => `${d.path} (${d.reason}${d.message === undefined ? "" : `: ${d.message}`})`)
|
|
181
|
+
.join(", ")}`, details);
|
|
171
182
|
}
|
|
172
183
|
}
|
|
173
184
|
/**
|
|
@@ -220,9 +231,11 @@ let AgentsService = class AgentsService {
|
|
|
220
231
|
const details = [...issues];
|
|
221
232
|
for (const key of Object.keys(def.toolPolicies)) {
|
|
222
233
|
if (!keys.has(key)) {
|
|
234
|
+
// an rc key (tool naming spec §8.3): saving writes current keys only, so name them
|
|
235
|
+
const renamed = legacyKeySaveText(key, keys);
|
|
223
236
|
details.push({
|
|
224
237
|
path: `toolPolicies.${key}`,
|
|
225
|
-
message: `"${key}" is not a tool of this agent`,
|
|
238
|
+
message: renamed ?? `"${key}" is not a tool of this agent`,
|
|
226
239
|
});
|
|
227
240
|
}
|
|
228
241
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type ModelParameter } from "@capybara-hq/plugin-sdk";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
import { type LegacyScope } from "../tools/legacy-keys.js";
|
|
3
4
|
/** 模型引用:供应商插件名 + 模型 id。 */
|
|
4
5
|
export declare const ModelRef: z.ZodObject<{
|
|
5
6
|
provider: z.ZodString;
|
|
@@ -34,11 +35,7 @@ export declare const AgentToolRef: z.ZodPreprocess<z.ZodDiscriminatedUnion<[z.Zo
|
|
|
34
35
|
tools: z.ZodUnion<readonly [z.ZodLiteral<"all">, z.ZodArray<z.ZodString>]>;
|
|
35
36
|
}, z.core.$strict>], "kind">, unknown>;
|
|
36
37
|
export type AgentToolRef = z.output<typeof AgentToolRef>;
|
|
37
|
-
|
|
38
|
-
* 新建 agent 未给 `tools` 时的默认工具(`tool_search` 由注册表按组织设置自动加入,不进定义)。
|
|
39
|
-
* 只用于创建请求;修改与读出旧版本都不注入默认值。
|
|
40
|
-
*/
|
|
41
|
-
export declare const DEFAULT_AGENT_TOOLS: AgentToolRef[];
|
|
38
|
+
export { DEFAULT_AGENT_TOOLS } from "../tools/builtin-names.js";
|
|
42
39
|
/** Roster names of inline templates and allowlisted org agents (the template name rule). */
|
|
43
40
|
export declare const SUBAGENT_NAME_RE: RegExp;
|
|
44
41
|
/**
|
|
@@ -75,7 +72,7 @@ export declare const InlineAgentTemplate: z.ZodObject<{
|
|
|
75
72
|
}, z.core.$strict>;
|
|
76
73
|
export type InlineAgentTemplate = z.infer<typeof InlineAgentTemplate>;
|
|
77
74
|
/**
|
|
78
|
-
* Sub-agents this agent may dispatch with the builtin `
|
|
75
|
+
* Sub-agents this agent may dispatch with the builtin `Agent` tool (phase C, spec §5.2). No
|
|
79
76
|
* default: definitions without it are unchanged and gain no version.
|
|
80
77
|
*/
|
|
81
78
|
export declare const SubagentsSchema: z.ZodObject<{
|
|
@@ -192,11 +189,37 @@ export declare const AgentDefinitionSchema: z.ZodObject<{
|
|
|
192
189
|
}, z.core.$strict>>;
|
|
193
190
|
}, z.core.$strip>;
|
|
194
191
|
export type AgentDefinition = z.infer<typeof AgentDefinitionSchema>;
|
|
192
|
+
/** The connectors and extensions a definition's own tool refs name (to read an ambiguous rc key). */
|
|
193
|
+
interface OwnRefs {
|
|
194
|
+
connectors: ReadonlySet<string>;
|
|
195
|
+
extensions: ReadonlySet<string>;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Release-candidate tool keys in a stored definition, read as current keys (tool naming spec
|
|
199
|
+
* §8.3), the way {@link normalizeToolRef} reads the app -> connector rename: builtin refs in
|
|
200
|
+
* `tools`, the keys of `toolPolicies`, and the `tools` / `disallowedTools` / `toolPolicies` of a
|
|
201
|
+
* template, the agent's inline sub-agent templates included. Works on an agent definition and on
|
|
202
|
+
* an agent template alike. Old builtin names map without `scope`; an rc `<x>__<tool>` key maps
|
|
203
|
+
* only with one (the org's connector slugs and their ids, the deployment's extension names). When
|
|
204
|
+
* `x` is both a slug and an extension name, the definition's own tool refs decide; when they
|
|
205
|
+
* cannot, a policy or a deny list keeps the restriction on both candidate keys (a deny is never
|
|
206
|
+
* lost) and an allowlist keeps the old key (inert). An unknown key stays as it is. Keys in the
|
|
207
|
+
* current format are never touched. Returns the same object when nothing changes. Saving never
|
|
208
|
+
* goes through this: a new definition with an old key is refused (`AgentsService`).
|
|
209
|
+
*/
|
|
210
|
+
export declare function normalizeToolKeys(definition: unknown, scope?: LegacyScope, inherited?: OwnRefs): unknown;
|
|
211
|
+
/**
|
|
212
|
+
* Does a stored definition or template hold an rc `<x>__<tool>` key, which only a
|
|
213
|
+
* {@link LegacyScope} can map? (Callers load the scope only then.)
|
|
214
|
+
*/
|
|
215
|
+
export declare function needsLegacyScope(definition: unknown): boolean;
|
|
195
216
|
/**
|
|
196
217
|
* 库里读出的定义(`agent_versions.definition`,不经 zod 解析):把改名前的 `{ kind: "app" }` 工具引用规范化为
|
|
197
|
-
* connector 形(C27
|
|
218
|
+
* connector 形(C27),and rc tool keys to current keys ({@link normalizeToolKeys}: builtins
|
|
219
|
+
* always, `<x>__<tool>` keys with `scope`). Other fields are kept; without old forms the same
|
|
220
|
+
* object is returned.
|
|
198
221
|
*/
|
|
199
|
-
export declare function normalizeStoredDefinition(def: unknown): AgentDefinition;
|
|
222
|
+
export declare function normalizeStoredDefinition(def: unknown, scope?: LegacyScope): AgentDefinition;
|
|
200
223
|
/** 按模型声明严格校验一组参数,返回 `{ path: "<field>.<key>", message }[]`(评测候选也用它)。 */
|
|
201
224
|
export declare function paramIssues(field: string, decl: ModelParameter[], params: Record<string, unknown>): {
|
|
202
225
|
path: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { validateParams } from "@capybara-hq/plugin-sdk";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
import { isLegacyBuiltinKey, isLegacyPrefixedKey, legacyToolKey, } from "../tools/legacy-keys.js";
|
|
3
4
|
/** 模型引用:供应商插件名 + 模型 id。 */
|
|
4
5
|
export const ModelRef = z.object({ provider: z.string(), model: z.string() });
|
|
5
6
|
/**
|
|
@@ -37,14 +38,7 @@ export const AgentToolRef = z.preprocess(normalizeToolRef, z.discriminatedUnion(
|
|
|
37
38
|
})
|
|
38
39
|
.strict(),
|
|
39
40
|
]));
|
|
40
|
-
|
|
41
|
-
* 新建 agent 未给 `tools` 时的默认工具(`tool_search` 由注册表按组织设置自动加入,不进定义)。
|
|
42
|
-
* 只用于创建请求;修改与读出旧版本都不注入默认值。
|
|
43
|
-
*/
|
|
44
|
-
export const DEFAULT_AGENT_TOOLS = [
|
|
45
|
-
{ kind: "builtin", name: "ask_user" },
|
|
46
|
-
{ kind: "builtin", name: "read_tool_output" },
|
|
47
|
-
];
|
|
41
|
+
export { DEFAULT_AGENT_TOOLS } from "../tools/builtin-names.js";
|
|
48
42
|
/** Roster names of inline templates and allowlisted org agents (the template name rule). */
|
|
49
43
|
export const SUBAGENT_NAME_RE = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
50
44
|
/**
|
|
@@ -68,7 +62,7 @@ export const InlineAgentTemplate = z
|
|
|
68
62
|
})
|
|
69
63
|
.strict();
|
|
70
64
|
/**
|
|
71
|
-
* Sub-agents this agent may dispatch with the builtin `
|
|
65
|
+
* Sub-agents this agent may dispatch with the builtin `Agent` tool (phase C, spec §5.2). No
|
|
72
66
|
* default: definitions without it are unchanged and gain no version.
|
|
73
67
|
*/
|
|
74
68
|
export const SubagentsSchema = z
|
|
@@ -118,7 +112,7 @@ export const AgentDefinitionSchema = z.object({
|
|
|
118
112
|
* 技能(M5 T13):`orgSkills` 是引用的组织技能 id(保存时校验属于本组织且未删除,不可重复)。
|
|
119
113
|
* agent 自己的技能(`scope=agent`)自动对它生效,不进定义。可省略(较早保存的定义也没有),按空处理;
|
|
120
114
|
* 不给默认值:没用技能的定义保存前后不变,不会因此多出一个版本。
|
|
121
|
-
* `writePolicy`(M6 T27,D10):私有 agent 的 `
|
|
115
|
+
* `writePolicy`(M6 T27,D10):私有 agent 的 `SkillWrite` 是否固定确认,缺省按 `allow`(不写进定义);
|
|
122
116
|
* 共享 agent 不论取值都走 R3 + R4。
|
|
123
117
|
*/
|
|
124
118
|
skills: z
|
|
@@ -136,20 +130,202 @@ export const AgentDefinitionSchema = z.object({
|
|
|
136
130
|
})
|
|
137
131
|
.strict()
|
|
138
132
|
.optional(),
|
|
139
|
-
/** Sub-agents (phase C); offered only when the builtin `
|
|
133
|
+
/** Sub-agents (phase C); offered only when the builtin `Agent` tool is in `tools`. */
|
|
140
134
|
subagents: SubagentsSchema.optional(),
|
|
141
135
|
});
|
|
136
|
+
const isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
137
|
+
/**
|
|
138
|
+
* The connector slugs and extension names `definition`'s `tools` name: connector refs (through
|
|
139
|
+
* `scope.connectorSlugById`), plugin refs, and current-format keys of a template's `tools`;
|
|
140
|
+
* `inherited` (the parent agent's, for an inline template) is added.
|
|
141
|
+
*/
|
|
142
|
+
function ownRefs(definition, scope, inherited) {
|
|
143
|
+
const connectors = new Set(inherited?.connectors);
|
|
144
|
+
const extensions = new Set(inherited?.extensions);
|
|
145
|
+
const tools = Array.isArray(definition.tools) ? definition.tools : [];
|
|
146
|
+
for (const r of tools) {
|
|
147
|
+
if (typeof r === "string") {
|
|
148
|
+
const m = /^(mcp|plugin)__([^_].*?)__./.exec(r);
|
|
149
|
+
if (m)
|
|
150
|
+
(m[1] === "mcp" ? connectors : extensions).add(m[2]);
|
|
151
|
+
}
|
|
152
|
+
else if (isRecord(r) && r.kind === "connector" && typeof r.connectorId === "string") {
|
|
153
|
+
const slug = scope.connectorSlugById?.get(r.connectorId);
|
|
154
|
+
if (slug !== undefined)
|
|
155
|
+
connectors.add(slug);
|
|
156
|
+
}
|
|
157
|
+
else if (isRecord(r) && r.kind === "plugin" && typeof r.plugin === "string") {
|
|
158
|
+
extensions.add(r.plugin);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return { connectors, extensions };
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* The current key(s) of a stored key. A builtin and an unambiguous `<x>__<tool>` map to one key
|
|
165
|
+
* ({@link legacyToolKey}). When `x` is both a connector slug and an extension name, the
|
|
166
|
+
* definition's own refs decide (only connector `x` -> `mcp__…`, only extension `x` ->
|
|
167
|
+
* `plugin__…`); when they name both or neither, both candidates are returned and the caller
|
|
168
|
+
* decides (a policy keeps a deny / ask on both: it must never be lost). Anything else: as is.
|
|
169
|
+
*/
|
|
170
|
+
function currentKeys(key, scope, own) {
|
|
171
|
+
const one = legacyToolKey(key, scope);
|
|
172
|
+
if (one !== null)
|
|
173
|
+
return [one];
|
|
174
|
+
if (scope === undefined || !isLegacyPrefixedKey(key))
|
|
175
|
+
return [key];
|
|
176
|
+
const head = key.slice(0, key.indexOf("__"));
|
|
177
|
+
if (!scope.connectorSlugs.has(head) || !scope.extensionNames.has(head))
|
|
178
|
+
return [key];
|
|
179
|
+
const c = own?.connectors.has(head) === true;
|
|
180
|
+
const e = own?.extensions.has(head) === true;
|
|
181
|
+
if (c && !e)
|
|
182
|
+
return [`mcp__${key}`];
|
|
183
|
+
if (e && !c)
|
|
184
|
+
return [`plugin__${key}`];
|
|
185
|
+
return [`mcp__${key}`, `plugin__${key}`];
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* A list of tool keys (a template's `tools` / `disallowedTools`) in current keys, deduplicated.
|
|
189
|
+
* A still-ambiguous key becomes both candidates in a deny list (`widen`), and stays as is (inert,
|
|
190
|
+
* so narrower) in an allowlist.
|
|
191
|
+
*/
|
|
192
|
+
function keyList(v, scope, own, widen) {
|
|
193
|
+
if (!Array.isArray(v))
|
|
194
|
+
return v;
|
|
195
|
+
let changed = false;
|
|
196
|
+
const out = [];
|
|
197
|
+
for (const x of v) {
|
|
198
|
+
let next = [x];
|
|
199
|
+
if (typeof x === "string") {
|
|
200
|
+
const keys = currentKeys(x, scope, own);
|
|
201
|
+
next = keys.length > 1 && !widen ? [x] : keys;
|
|
202
|
+
}
|
|
203
|
+
if (next.length !== 1 || next[0] !== x)
|
|
204
|
+
changed = true;
|
|
205
|
+
for (const n of next) {
|
|
206
|
+
if (typeof n === "string" && out.includes(n)) {
|
|
207
|
+
changed = true;
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
out.push(n);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return changed ? out : v;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* `toolPolicies` in current keys; keys that become one keep the stricter policy, and a
|
|
217
|
+
* still-ambiguous key keeps its `ask` / `deny` on both candidates (anything else is dropped).
|
|
218
|
+
*/
|
|
219
|
+
function policyKeys(v, scope, own) {
|
|
220
|
+
if (!isRecord(v))
|
|
221
|
+
return v;
|
|
222
|
+
const mapped = Object.entries(v).map(([k, p]) => [k, p, currentKeys(k, scope, own)]);
|
|
223
|
+
if (mapped.every(([k, , keys]) => keys.length === 1 && keys[0] === k))
|
|
224
|
+
return v;
|
|
225
|
+
const rank = (p) => (p === "deny" ? 2 : p === "ask" ? 1 : 0);
|
|
226
|
+
const out = {};
|
|
227
|
+
for (const [, p, keys] of mapped) {
|
|
228
|
+
if (keys.length > 1 && rank(p) === 0)
|
|
229
|
+
continue;
|
|
230
|
+
for (const next of keys) {
|
|
231
|
+
if (!Object.hasOwn(out, next) || rank(p) > rank(out[next]))
|
|
232
|
+
out[next] = p;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return out;
|
|
236
|
+
}
|
|
237
|
+
/** An agent definition's `tools`: builtin refs by their current names (connector and plugin refs name tools, not keys). */
|
|
238
|
+
function toolRefs(v, scope, own) {
|
|
239
|
+
if (!Array.isArray(v))
|
|
240
|
+
return v;
|
|
241
|
+
// template-shaped (`tools: string[]`): an allowlist
|
|
242
|
+
if (v.some((x) => typeof x === "string"))
|
|
243
|
+
return keyList(v, scope, own, false);
|
|
244
|
+
if (!v.some((r) => isRecord(r) &&
|
|
245
|
+
r.kind === "builtin" &&
|
|
246
|
+
typeof r.name === "string" &&
|
|
247
|
+
isLegacyBuiltinKey(r.name))) {
|
|
248
|
+
return v;
|
|
249
|
+
}
|
|
250
|
+
return v.map((r) => isRecord(r) && r.kind === "builtin" && typeof r.name === "string"
|
|
251
|
+
? { ...r, name: legacyToolKey(r.name) ?? r.name }
|
|
252
|
+
: r);
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Release-candidate tool keys in a stored definition, read as current keys (tool naming spec
|
|
256
|
+
* §8.3), the way {@link normalizeToolRef} reads the app -> connector rename: builtin refs in
|
|
257
|
+
* `tools`, the keys of `toolPolicies`, and the `tools` / `disallowedTools` / `toolPolicies` of a
|
|
258
|
+
* template, the agent's inline sub-agent templates included. Works on an agent definition and on
|
|
259
|
+
* an agent template alike. Old builtin names map without `scope`; an rc `<x>__<tool>` key maps
|
|
260
|
+
* only with one (the org's connector slugs and their ids, the deployment's extension names). When
|
|
261
|
+
* `x` is both a slug and an extension name, the definition's own tool refs decide; when they
|
|
262
|
+
* cannot, a policy or a deny list keeps the restriction on both candidate keys (a deny is never
|
|
263
|
+
* lost) and an allowlist keeps the old key (inert). An unknown key stays as it is. Keys in the
|
|
264
|
+
* current format are never touched. Returns the same object when nothing changes. Saving never
|
|
265
|
+
* goes through this: a new definition with an old key is refused (`AgentsService`).
|
|
266
|
+
*/
|
|
267
|
+
export function normalizeToolKeys(definition, scope, inherited) {
|
|
268
|
+
if (!isRecord(definition))
|
|
269
|
+
return definition;
|
|
270
|
+
const own = scope === undefined ? undefined : ownRefs(definition, scope, inherited);
|
|
271
|
+
const next = { ...definition };
|
|
272
|
+
let changed = false;
|
|
273
|
+
const put = (field, value) => {
|
|
274
|
+
if (value === definition[field])
|
|
275
|
+
return;
|
|
276
|
+
next[field] = value;
|
|
277
|
+
changed = true;
|
|
278
|
+
};
|
|
279
|
+
if ("tools" in definition)
|
|
280
|
+
put("tools", toolRefs(definition.tools, scope, own));
|
|
281
|
+
if ("disallowedTools" in definition) {
|
|
282
|
+
put("disallowedTools", keyList(definition.disallowedTools, scope, own, true));
|
|
283
|
+
}
|
|
284
|
+
if ("toolPolicies" in definition) {
|
|
285
|
+
put("toolPolicies", policyKeys(definition.toolPolicies, scope, own));
|
|
286
|
+
}
|
|
287
|
+
const sub = definition.subagents;
|
|
288
|
+
if (isRecord(sub) && Array.isArray(sub.inline)) {
|
|
289
|
+
const inline = sub.inline.map((t) => normalizeToolKeys(t, scope, own));
|
|
290
|
+
if (inline.some((t, i) => t !== sub.inline[i])) {
|
|
291
|
+
put("subagents", { ...sub, inline });
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return changed ? next : definition;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Does a stored definition or template hold an rc `<x>__<tool>` key, which only a
|
|
298
|
+
* {@link LegacyScope} can map? (Callers load the scope only then.)
|
|
299
|
+
*/
|
|
300
|
+
export function needsLegacyScope(definition) {
|
|
301
|
+
if (!isRecord(definition))
|
|
302
|
+
return false;
|
|
303
|
+
const lists = [definition.tools, definition.disallowedTools];
|
|
304
|
+
for (const l of lists) {
|
|
305
|
+
if (Array.isArray(l) && l.some((x) => typeof x === "string" && isLegacyPrefixedKey(x))) {
|
|
306
|
+
return true;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
if (isRecord(definition.toolPolicies)) {
|
|
310
|
+
if (Object.keys(definition.toolPolicies).some(isLegacyPrefixedKey))
|
|
311
|
+
return true;
|
|
312
|
+
}
|
|
313
|
+
const sub = definition.subagents;
|
|
314
|
+
return isRecord(sub) && Array.isArray(sub.inline) && sub.inline.some(needsLegacyScope);
|
|
315
|
+
}
|
|
142
316
|
/**
|
|
143
317
|
* 库里读出的定义(`agent_versions.definition`,不经 zod 解析):把改名前的 `{ kind: "app" }` 工具引用规范化为
|
|
144
|
-
* connector 形(C27
|
|
318
|
+
* connector 形(C27),and rc tool keys to current keys ({@link normalizeToolKeys}: builtins
|
|
319
|
+
* always, `<x>__<tool>` keys with `scope`). Other fields are kept; without old forms the same
|
|
320
|
+
* object is returned.
|
|
145
321
|
*/
|
|
146
|
-
export function normalizeStoredDefinition(def) {
|
|
147
|
-
|
|
322
|
+
export function normalizeStoredDefinition(def, scope) {
|
|
323
|
+
let d = def;
|
|
148
324
|
const tools = d.tools;
|
|
149
|
-
if (
|
|
150
|
-
|
|
325
|
+
if (Array.isArray(tools) && tools.some((t) => t?.kind === "app")) {
|
|
326
|
+
d = { ...d, tools: tools.map(normalizeToolRef) };
|
|
151
327
|
}
|
|
152
|
-
return
|
|
328
|
+
return normalizeToolKeys(d, scope);
|
|
153
329
|
}
|
|
154
330
|
/** 按模型声明严格校验一组参数,返回 `{ path: "<field>.<key>", message }[]`(评测候选也用它)。 */
|
|
155
331
|
export function paramIssues(field, decl, params) {
|
package/dist/agents/templates.js
CHANGED
|
@@ -10,7 +10,9 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
10
10
|
import { randomUUID } from "node:crypto";
|
|
11
11
|
import { Inject, Injectable } from "@nestjs/common";
|
|
12
12
|
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
13
|
+
import { loadLegacyScope } from "../tools/legacy-data.js";
|
|
13
14
|
import { canonicalJson } from "../tools/registry.js";
|
|
15
|
+
import { needsLegacyScope, normalizeToolKeys } from "./definition.js";
|
|
14
16
|
const baseQuery = (db, orgId) => db
|
|
15
17
|
.selectFrom("agent_templates as t")
|
|
16
18
|
.innerJoin("agent_template_versions as v", (j) => j.onRef("v.template_id", "=", "t.id").onRef("v.version", "=", "t.current_version"))
|
|
@@ -26,16 +28,27 @@ const baseQuery = (db, orgId) => db
|
|
|
26
28
|
])
|
|
27
29
|
.where("t.org_id", "=", orgId)
|
|
28
30
|
.where("t.deleted_at", "is", null);
|
|
29
|
-
|
|
31
|
+
/**
|
|
32
|
+
* A stored template row; its tool keys read as current keys (tool naming spec §8.3): old builtin
|
|
33
|
+
* names always, rc `<x>__<tool>` keys with `scope` (see {@link scopedRows}).
|
|
34
|
+
*/
|
|
35
|
+
const rowOf = (r, scope) => ({
|
|
30
36
|
id: r.id,
|
|
31
37
|
name: r.name,
|
|
32
38
|
plugin: r.plugin_name,
|
|
33
39
|
version: r.current_version,
|
|
34
|
-
template: r.definition,
|
|
40
|
+
template: normalizeToolKeys(r.definition, scope),
|
|
35
41
|
sourceFormat: r.source_format,
|
|
36
42
|
catalogItemId: r.catalog_item_id,
|
|
37
43
|
catalogVersion: r.catalog_version,
|
|
38
44
|
});
|
|
45
|
+
/** The rows of one org as {@link TemplateRow}s, reading the org's legacy scope once when needed. */
|
|
46
|
+
async function scopedRows(db, orgId, rows) {
|
|
47
|
+
const scope = rows.some((r) => needsLegacyScope(r.definition))
|
|
48
|
+
? await loadLegacyScope(db, orgId)
|
|
49
|
+
: undefined;
|
|
50
|
+
return rows.map((r) => rowOf(r, scope));
|
|
51
|
+
}
|
|
39
52
|
/** The live templates of `ids` in the org (deleted and foreign ids are left out), by id. */
|
|
40
53
|
export async function loadTemplates(db, orgId, ids) {
|
|
41
54
|
if (ids.length === 0)
|
|
@@ -43,7 +56,7 @@ export async function loadTemplates(db, orgId, ids) {
|
|
|
43
56
|
const rows = await baseQuery(db, orgId)
|
|
44
57
|
.where("t.id", "in", [...ids])
|
|
45
58
|
.execute();
|
|
46
|
-
return new Map(rows.map((
|
|
59
|
+
return new Map((await scopedRows(db, orgId, rows)).map((t) => [t.id, t]));
|
|
47
60
|
}
|
|
48
61
|
/** Reads the org's agent templates (consumed by the roster, the agent page and Task 19's API). */
|
|
49
62
|
let AgentTemplatesService = class AgentTemplatesService {
|
|
@@ -84,7 +97,9 @@ let AgentTemplatesService = class AgentTemplatesService {
|
|
|
84
97
|
const r = await q.executeTakeFirst();
|
|
85
98
|
if (!r)
|
|
86
99
|
return null;
|
|
87
|
-
const t =
|
|
100
|
+
const [t] = await scopedRows(this.db.db, orgId, [r]);
|
|
101
|
+
if (!t)
|
|
102
|
+
return null;
|
|
88
103
|
return { id: t.id, version: t.version, plugin: t.plugin, template: t.template };
|
|
89
104
|
}
|
|
90
105
|
};
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// module whose provider injects PluginInstaller (an ESM import cycle would run decorators early).
|
|
5
5
|
import { createHash } from "node:crypto";
|
|
6
6
|
import { parseAgentTemplate, parseConnectorTemplateFile, } from "@capybara-hq/plugin-sdk";
|
|
7
|
+
import { normalizeToolKeys } from "../agents/definition.js";
|
|
7
8
|
import { ApiError } from "../errors.js";
|
|
8
9
|
import { can } from "../orgs/roles.js";
|
|
9
10
|
import { packagePath } from "../packages/tgz.js";
|
|
@@ -318,6 +319,8 @@ export async function readCatalogAgentTemplates(storage, v) {
|
|
|
318
319
|
if (!parsed || "errors" in parsed) {
|
|
319
320
|
throw new ApiError("internal", `Stored agent template ${path} is missing or invalid`);
|
|
320
321
|
}
|
|
321
|
-
|
|
322
|
+
// an rc package's template may name old builtins: read as the current names (tool naming
|
|
323
|
+
// spec §8.3); rc `<x>__<tool>` keys are read with the org's scope by `loadTemplates`
|
|
324
|
+
return { path, template: normalizeToolKeys(parsed.template) };
|
|
322
325
|
});
|
|
323
326
|
}
|
|
@@ -13,16 +13,19 @@ import { item } from "./report.js";
|
|
|
13
13
|
export const GENERATED_AGENTS_DIR = ".capybara-generated/agents";
|
|
14
14
|
/** Claude Code tool names -> Capybara tool keys (spec §16.4; anything else is dropped). */
|
|
15
15
|
const TOOL_MAP = {
|
|
16
|
-
Bash: "
|
|
17
|
-
Read: "
|
|
18
|
-
Write: "
|
|
19
|
-
Edit: "
|
|
20
|
-
MultiEdit: "
|
|
21
|
-
Glob: "
|
|
22
|
-
Grep: "
|
|
23
|
-
Skill: "
|
|
24
|
-
|
|
25
|
-
ToolSearch: "
|
|
16
|
+
Bash: "Bash",
|
|
17
|
+
Read: "Read",
|
|
18
|
+
Write: "Write",
|
|
19
|
+
Edit: "Edit",
|
|
20
|
+
MultiEdit: "Edit",
|
|
21
|
+
Glob: "Glob",
|
|
22
|
+
Grep: "Grep",
|
|
23
|
+
Skill: "Skill",
|
|
24
|
+
AskUserQuestion: "AskUserQuestion",
|
|
25
|
+
ToolSearch: "ToolSearch",
|
|
26
|
+
Agent: "Agent",
|
|
27
|
+
Task: "Agent",
|
|
28
|
+
TodoWrite: "plugin__todo__write",
|
|
26
29
|
};
|
|
27
30
|
/** Claude ignores these for plugin agents: `not_applicable`. */
|
|
28
31
|
const NOT_APPLICABLE = new Set(["permissionMode", "hooks", "mcpServers"]);
|
|
@@ -164,7 +164,7 @@ export declare function headsToResolve(entries: readonly MarketplaceEntry[], imp
|
|
|
164
164
|
/** The host versions (an entry's `minKernel` is judged against them). */
|
|
165
165
|
export declare const HOST_VERSIONS: {
|
|
166
166
|
readonly kernel: string;
|
|
167
|
-
readonly sdk: "0.1.0-rc.
|
|
167
|
+
readonly sdk: "0.1.0-rc.1";
|
|
168
168
|
};
|
|
169
169
|
/** Whether this deployment satisfies the entry's `minKernel`. */
|
|
170
170
|
export declare const entryCompatible: (e: Pick<MarketplaceEntry, "minKernel">) => boolean;
|
package/dist/channels/cards.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ChannelCard, type FormAnswer, type InputForm, type OutboundMessage } from "@capybara-hq/plugin-sdk";
|
|
2
2
|
import type { KernelSchemaDb } from "../db/kernel-schema.js";
|
|
3
|
-
import type { ApprovalsService } from "../tools/approvals.service.js";
|
|
3
|
+
import type { ApprovalsService, ApprovalView } from "../tools/approvals.service.js";
|
|
4
4
|
import { type ChannelLocale } from "./phrases.js";
|
|
5
5
|
/** 审批卡片里工具参数预览的最大长度(字符)。 */
|
|
6
6
|
export declare const INPUT_PREVIEW_MAX = 500;
|
|
@@ -23,6 +23,12 @@ export declare function webBase(publicUrl: string | undefined): string | undefin
|
|
|
23
23
|
export declare const conversationUrl: (base: string, conversationId: string) => string;
|
|
24
24
|
/** 个人连接页里某个连接器的位置(与网页 ConnectCard 的链接一致)。 */
|
|
25
25
|
export declare const connectUrl: (base: string, connectorId: string) => string;
|
|
26
|
+
/**
|
|
27
|
+
* The tool as the card names it (tool naming spec §7): a builtin by its name; a connector or
|
|
28
|
+
* extension tool as `<display name> [<tool>]` (the connector's name, the plugin's display name in
|
|
29
|
+
* the card's language), the way the web labels it.
|
|
30
|
+
*/
|
|
31
|
+
export declare function approvalToolName(v: Pick<ApprovalView, "toolKey" | "toolName" | "connector" | "extension">, locale: ChannelLocale): string;
|
|
26
32
|
export interface CardDeps {
|
|
27
33
|
db: KernelSchemaDb;
|
|
28
34
|
approvals: Pick<ApprovalsService, "describe">;
|
package/dist/channels/cards.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { parseToolKey, } from "@capybara-hq/plugin-sdk";
|
|
2
2
|
import { phrase } from "./phrases.js";
|
|
3
3
|
/** 审批卡片里工具参数预览的最大长度(字符)。 */
|
|
4
4
|
export const INPUT_PREVIEW_MAX = 500;
|
|
@@ -84,12 +84,20 @@ export function webBase(publicUrl) {
|
|
|
84
84
|
export const conversationUrl = (base, conversationId) => `${base}/chat/${conversationId}`;
|
|
85
85
|
/** 个人连接页里某个连接器的位置(与网页 ConnectCard 的链接一致)。 */
|
|
86
86
|
export const connectUrl = (base, connectorId) => `${base}/settings/connections#connector-${encodeURIComponent(connectorId)}`;
|
|
87
|
-
/**
|
|
88
|
-
|
|
87
|
+
/**
|
|
88
|
+
* The tool as the card names it (tool naming spec §7): a builtin by its name; a connector or
|
|
89
|
+
* extension tool as `<display name> [<tool>]` (the connector's name, the plugin's display name in
|
|
90
|
+
* the card's language), the way the web labels it.
|
|
91
|
+
*/
|
|
92
|
+
export function approvalToolName(v, locale) {
|
|
93
|
+
// `toolName` is already the connector's own name for its tool
|
|
89
94
|
if (v.connector)
|
|
90
|
-
return v.toolName
|
|
91
|
-
const
|
|
92
|
-
|
|
95
|
+
return `${v.connector.name} [${v.toolName}]`;
|
|
96
|
+
const parsed = parseToolKey(v.toolKey);
|
|
97
|
+
const tool = parsed && parsed.kind !== "builtin" ? parsed.tool : v.toolName;
|
|
98
|
+
if (v.extension)
|
|
99
|
+
return `${v.extension.displayName[locale]} [${tool}]`;
|
|
100
|
+
return v.toolKey;
|
|
93
101
|
}
|
|
94
102
|
/** 账号显示名;不存在返回 undefined。 */
|
|
95
103
|
async function displayName(db, accountId) {
|
|
@@ -115,8 +123,8 @@ export async function approvalCard(d, approvalId, base, locale, redact) {
|
|
|
115
123
|
kind: "approval",
|
|
116
124
|
id: v.id,
|
|
117
125
|
title: phrase("approvalTitle", locale),
|
|
118
|
-
|
|
119
|
-
|
|
126
|
+
// the label carries the source, so no separate appName (renderers would repeat it)
|
|
127
|
+
toolName: approvalToolName(v, locale),
|
|
120
128
|
agentName: v.agent.name || "Agent",
|
|
121
129
|
inputPreview: inputPreview(v.input, redact),
|
|
122
130
|
scopes: v.requestedFor === null ? ["once"] : ["once", "session", "always"],
|
package/dist/config/schema.js
CHANGED
|
@@ -751,7 +751,7 @@ export const KernelConfigSchema = z.object({
|
|
|
751
751
|
.int()
|
|
752
752
|
.positive()
|
|
753
753
|
.default(20000)
|
|
754
|
-
.meta(meta({ description: "Maximum characters returned by one
|
|
754
|
+
.meta(meta({ description: "Maximum characters returned by one ReadToolOutput call" })),
|
|
755
755
|
oauthAllowInsecureLoopback: z
|
|
756
756
|
.boolean()
|
|
757
757
|
.default(false)
|
|
@@ -978,7 +978,7 @@ export const KernelConfigSchema = z.object({
|
|
|
978
978
|
.positive()
|
|
979
979
|
.default(104_857_600)
|
|
980
980
|
.meta(meta({
|
|
981
|
-
description: "Largest file in bytes an agent may deliver from its sandbox to the user as an artifact (
|
|
981
|
+
description: "Largest file in bytes an agent may deliver from its sandbox to the user as an artifact (Deliver)",
|
|
982
982
|
})),
|
|
983
983
|
limits: z
|
|
984
984
|
.object({
|
|
@@ -20,7 +20,7 @@ export interface ArtifactPreview {
|
|
|
20
20
|
truncated: boolean;
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
|
-
* 产物(M5 T8 / T11):agent 经 `
|
|
23
|
+
* 产物(M5 T8 / T11):agent 经 `Deliver` 交付的文件。先按会话流的规则判定会话可见
|
|
24
24
|
* (不可见 → `conversation.not_found`),再只在这个会话的日志里找 `artifact_created`
|
|
25
25
|
* (没有 → `conversation.artifact_not_found`)。
|
|
26
26
|
*
|
|
@@ -62,7 +62,7 @@ async function readPrefix(body, max) {
|
|
|
62
62
|
return out.subarray(0, n);
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
|
-
* 产物(M5 T8 / T11):agent 经 `
|
|
65
|
+
* 产物(M5 T8 / T11):agent 经 `Deliver` 交付的文件。先按会话流的规则判定会话可见
|
|
66
66
|
* (不可见 → `conversation.not_found`),再只在这个会话的日志里找 `artifact_created`
|
|
67
67
|
* (没有 → `conversation.artifact_not_found`)。
|
|
68
68
|
*
|
|
@@ -123,6 +123,17 @@ export declare class EventLog {
|
|
|
123
123
|
latestOfType<T extends ConversationEventType>(conversationId: string, type: T): Promise<Extract<ConversationEvent, {
|
|
124
124
|
type: T;
|
|
125
125
|
}> | undefined>;
|
|
126
|
+
/**
|
|
127
|
+
* The file state (`tool_result.view.file`) the latest `Read` / `Write` / `Edit` result of this
|
|
128
|
+
* conversation recorded for `path` (a normalized sandbox path); null when none did. One index
|
|
129
|
+
* probe per call: the partial index `conversation_events_file_state_idx` of migration 0063
|
|
130
|
+
* (conversation_id, view.file.path, seq DESC; tool_result rows only) answers it, also for a path
|
|
131
|
+
* never read (the query's predicate must keep matching that index's expression).
|
|
132
|
+
*/
|
|
133
|
+
latestFileState(conversationId: string, path: string): Promise<{
|
|
134
|
+
size: number;
|
|
135
|
+
sha256: string;
|
|
136
|
+
} | null>;
|
|
126
137
|
private validate;
|
|
127
138
|
/** The append itself, in the context's transaction (both callers open or join one). */
|
|
128
139
|
private write;
|