@openagentpack/sdk 0.3.0 → 0.3.1
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/index.d.ts +43 -1
- package/dist/index.js +597 -283
- package/dist/session-events.js +21 -5
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -24,6 +24,178 @@ var UserError = class extends Error {
|
|
|
24
24
|
}
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
+
// src/internal/transport.ts
|
|
28
|
+
var defaultFetch;
|
|
29
|
+
function setDefaultFetch(fetchImpl) {
|
|
30
|
+
defaultFetch = fetchImpl;
|
|
31
|
+
}
|
|
32
|
+
function resolveFetch() {
|
|
33
|
+
return defaultFetch ?? ((input, init) => fetch(input, init));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// src/internal/providers/base-client.ts
|
|
37
|
+
var ApiError = class _ApiError extends Error {
|
|
38
|
+
constructor(statusCode, responseBody, prefix) {
|
|
39
|
+
super(`${prefix} ${statusCode}: ${responseBody}`);
|
|
40
|
+
this.statusCode = statusCode;
|
|
41
|
+
this.responseBody = responseBody;
|
|
42
|
+
}
|
|
43
|
+
statusCode;
|
|
44
|
+
responseBody;
|
|
45
|
+
static isNotFound(err) {
|
|
46
|
+
return err instanceof _ApiError && err.statusCode === 404;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var ConflictError = class extends ApiError {
|
|
50
|
+
};
|
|
51
|
+
var BaseApiClient = class {
|
|
52
|
+
isConflict(_status, _body) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
async throwIfError(res) {
|
|
56
|
+
if (res.ok) return;
|
|
57
|
+
const body = await res.text();
|
|
58
|
+
if (this.isConflict(res.status, body)) throw new ConflictError(res.status, body, this.errorPrefix);
|
|
59
|
+
throw new ApiError(res.status, body, this.errorPrefix);
|
|
60
|
+
}
|
|
61
|
+
async post(path, body) {
|
|
62
|
+
const res = await resolveFetch()(`${this.baseUrl}${path}`, {
|
|
63
|
+
method: "POST",
|
|
64
|
+
headers: this.headers(),
|
|
65
|
+
body: JSON.stringify(body)
|
|
66
|
+
});
|
|
67
|
+
await this.throwIfError(res);
|
|
68
|
+
return res.json();
|
|
69
|
+
}
|
|
70
|
+
async put(path, body) {
|
|
71
|
+
const res = await resolveFetch()(`${this.baseUrl}${path}`, {
|
|
72
|
+
method: "PUT",
|
|
73
|
+
headers: this.headers(),
|
|
74
|
+
body: JSON.stringify(body)
|
|
75
|
+
});
|
|
76
|
+
await this.throwIfError(res);
|
|
77
|
+
return res.json();
|
|
78
|
+
}
|
|
79
|
+
async delete(path) {
|
|
80
|
+
const res = await resolveFetch()(`${this.baseUrl}${path}`, {
|
|
81
|
+
method: "DELETE",
|
|
82
|
+
headers: this.headers()
|
|
83
|
+
});
|
|
84
|
+
await this.throwIfError(res);
|
|
85
|
+
}
|
|
86
|
+
async get(path) {
|
|
87
|
+
const res = await resolveFetch()(`${this.baseUrl}${path}`, {
|
|
88
|
+
method: "GET",
|
|
89
|
+
headers: this.headers()
|
|
90
|
+
});
|
|
91
|
+
await this.throwIfError(res);
|
|
92
|
+
return res.json();
|
|
93
|
+
}
|
|
94
|
+
async getBuffer(path) {
|
|
95
|
+
const res = await resolveFetch()(`${this.baseUrl}${path}`, {
|
|
96
|
+
method: "GET",
|
|
97
|
+
headers: this.headers()
|
|
98
|
+
});
|
|
99
|
+
await this.throwIfError(res);
|
|
100
|
+
return Buffer.from(await res.arrayBuffer());
|
|
101
|
+
}
|
|
102
|
+
async *sse(path, options) {
|
|
103
|
+
const controller = new AbortController();
|
|
104
|
+
const res = await resolveFetch()(`${this.baseUrl}${path}`, {
|
|
105
|
+
method: "GET",
|
|
106
|
+
headers: { ...this.headers(), Accept: "text/event-stream", ...options?.headers },
|
|
107
|
+
signal: controller.signal
|
|
108
|
+
});
|
|
109
|
+
await this.throwIfError(res);
|
|
110
|
+
const reader = res.body.getReader();
|
|
111
|
+
const decoder = new TextDecoder();
|
|
112
|
+
let buffer = "";
|
|
113
|
+
try {
|
|
114
|
+
while (true) {
|
|
115
|
+
const { done, value } = await reader.read();
|
|
116
|
+
if (done) break;
|
|
117
|
+
buffer += decoder.decode(value, { stream: true });
|
|
118
|
+
let boundary = buffer.indexOf("\n\n");
|
|
119
|
+
while (boundary !== -1) {
|
|
120
|
+
const frame = buffer.slice(0, boundary);
|
|
121
|
+
buffer = buffer.slice(boundary + 2);
|
|
122
|
+
boundary = buffer.indexOf("\n\n");
|
|
123
|
+
const dataLines = [];
|
|
124
|
+
let sseId;
|
|
125
|
+
for (const line of frame.split("\n")) {
|
|
126
|
+
if (line.startsWith(":")) continue;
|
|
127
|
+
if (line.startsWith("event:") && line.slice(6).trim() === "heartbeat") {
|
|
128
|
+
dataLines.length = 0;
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
if (line.startsWith("data:")) {
|
|
132
|
+
dataLines.push(line.slice(5).trimStart());
|
|
133
|
+
}
|
|
134
|
+
if (line.startsWith("id:")) {
|
|
135
|
+
sseId = line.slice(3).trimStart();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (dataLines.length === 0) continue;
|
|
139
|
+
const json = dataLines.join("\n");
|
|
140
|
+
try {
|
|
141
|
+
const parsed = JSON.parse(json);
|
|
142
|
+
if (sseId !== void 0 && parsed.id === void 0) {
|
|
143
|
+
parsed.id = sseId;
|
|
144
|
+
}
|
|
145
|
+
yield parsed;
|
|
146
|
+
} catch {
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
} finally {
|
|
151
|
+
try {
|
|
152
|
+
await reader.cancel();
|
|
153
|
+
} catch {
|
|
154
|
+
}
|
|
155
|
+
controller.abort();
|
|
156
|
+
reader.releaseLock();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
async postFormData(path, formData) {
|
|
160
|
+
const { "Content-Type": _contentType, ...headers } = this.headers();
|
|
161
|
+
const res = await resolveFetch()(`${this.baseUrl}${path}`, {
|
|
162
|
+
method: "POST",
|
|
163
|
+
headers,
|
|
164
|
+
body: formData
|
|
165
|
+
});
|
|
166
|
+
await this.throwIfError(res);
|
|
167
|
+
return res.json();
|
|
168
|
+
}
|
|
169
|
+
async getAllPaged(path) {
|
|
170
|
+
const all = [];
|
|
171
|
+
let cursor;
|
|
172
|
+
for (; ; ) {
|
|
173
|
+
const sep = path.includes("?") ? "&" : "?";
|
|
174
|
+
const param = this.paginationStrategy === "page" ? "page" : "after_id";
|
|
175
|
+
const url = cursor ? `${path}${sep}limit=100&${param}=${encodeURIComponent(cursor)}` : `${path}${sep}limit=100`;
|
|
176
|
+
const res = await this.get(url);
|
|
177
|
+
const data = res.data ?? [];
|
|
178
|
+
all.push(...data);
|
|
179
|
+
if (data.length === 0) break;
|
|
180
|
+
if (this.paginationStrategy === "page") {
|
|
181
|
+
if (!res.next_page) break;
|
|
182
|
+
cursor = res.next_page;
|
|
183
|
+
} else {
|
|
184
|
+
if (!res.has_more || !res.last_id) break;
|
|
185
|
+
cursor = res.last_id;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return all;
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
function toRemoteResource(res) {
|
|
192
|
+
return {
|
|
193
|
+
id: res.id,
|
|
194
|
+
type: res.type,
|
|
195
|
+
version: res.version
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
27
199
|
// src/internal/providers/capabilities.ts
|
|
28
200
|
function isSupported(caps, kind) {
|
|
29
201
|
const tier = caps?.[kind]?.tier;
|
|
@@ -80,6 +252,16 @@ function getProvider(name) {
|
|
|
80
252
|
function allProviders() {
|
|
81
253
|
return Array.from(registry.values());
|
|
82
254
|
}
|
|
255
|
+
function parseProviderConfig(def, rawConfig) {
|
|
256
|
+
const result = def.configSchema.safeParse(rawConfig);
|
|
257
|
+
if (result.success) return result.data;
|
|
258
|
+
const details = result.error.issues.map((issue) => {
|
|
259
|
+
const path = issue.path.join(".");
|
|
260
|
+
return path ? `${path}: ${issue.message}` : issue.message;
|
|
261
|
+
});
|
|
262
|
+
throw new UserError(`Provider '${def.name}' config invalid:
|
|
263
|
+
${details.join("\n")}`);
|
|
264
|
+
}
|
|
83
265
|
function buildProviders(providersConfig, projectName) {
|
|
84
266
|
const adapters = /* @__PURE__ */ new Map();
|
|
85
267
|
for (const [name, rawConfig] of Object.entries(providersConfig)) {
|
|
@@ -87,7 +269,7 @@ function buildProviders(providersConfig, projectName) {
|
|
|
87
269
|
if (!def) {
|
|
88
270
|
throw new UserError(`Unknown provider '${name}'. Registered: ${Array.from(registry.keys()).join(", ")}`);
|
|
89
271
|
}
|
|
90
|
-
const parsed = def
|
|
272
|
+
const parsed = parseProviderConfig(def, rawConfig);
|
|
91
273
|
const adapter2 = def.createAdapter(parsed, projectName);
|
|
92
274
|
validateProviderFacets(def, adapter2);
|
|
93
275
|
adapters.set(name, adapter2);
|
|
@@ -97,8 +279,11 @@ function buildProviders(providersConfig, projectName) {
|
|
|
97
279
|
var PROVIDER_ENV_VARS = {
|
|
98
280
|
bailian: {
|
|
99
281
|
api_key: { env: ["DASHSCOPE_API_KEY", "BAILIAN_API_KEY"], required: true },
|
|
100
|
-
workspace_id
|
|
101
|
-
|
|
282
|
+
// Neither workspace_id nor base_url is required on its own; the config schema
|
|
283
|
+
// enforces "at least one" so a host can supply just base_url (BAILIAN_BASE_URL).
|
|
284
|
+
// base_url is the preferred placeholder emitted by `agents sync`.
|
|
285
|
+
workspace_id: { env: ["BAILIAN_WORKSPACE_ID"], required: false },
|
|
286
|
+
base_url: { env: ["BAILIAN_BASE_URL"], required: false, placeholder: true }
|
|
102
287
|
},
|
|
103
288
|
qoder: {
|
|
104
289
|
api_key: { env: ["QODER_PAT", "QODER_API_KEY"], required: true },
|
|
@@ -117,8 +302,8 @@ function placeholderProviderConfig(providerName) {
|
|
|
117
302
|
const envMap = PROVIDER_ENV_VARS[providerName];
|
|
118
303
|
if (!envMap) return {};
|
|
119
304
|
const out = {};
|
|
120
|
-
for (const [field, { env, required }] of Object.entries(envMap)) {
|
|
121
|
-
if (required && env[0]) out[field] = `\${${env[0]}}`;
|
|
305
|
+
for (const [field, { env, required, placeholder }] of Object.entries(envMap)) {
|
|
306
|
+
if ((required || placeholder) && env[0]) out[field] = `\${${env[0]}}`;
|
|
122
307
|
}
|
|
123
308
|
return out;
|
|
124
309
|
}
|
|
@@ -156,7 +341,7 @@ function buildProviderFromEnv(providerName, projectName) {
|
|
|
156
341
|
throw new UserError(`Unknown provider '${providerName}'. Registered: ${Array.from(registry.keys()).join(", ")}`);
|
|
157
342
|
}
|
|
158
343
|
const config = resolveProviderConfigFromEnv(providerName);
|
|
159
|
-
const parsed = def
|
|
344
|
+
const parsed = parseProviderConfig(def, config);
|
|
160
345
|
const adapter2 = def.createAdapter(parsed, projectName);
|
|
161
346
|
validateProviderFacets(def, adapter2);
|
|
162
347
|
return adapter2;
|
|
@@ -210,161 +395,6 @@ function skillNameFromFiles(files) {
|
|
|
210
395
|
return match?.[1]?.replace(/^["']|["']$/g, "") || void 0;
|
|
211
396
|
}
|
|
212
397
|
|
|
213
|
-
// src/internal/providers/base-client.ts
|
|
214
|
-
var ApiError = class _ApiError extends Error {
|
|
215
|
-
constructor(statusCode, responseBody, prefix) {
|
|
216
|
-
super(`${prefix} ${statusCode}: ${responseBody}`);
|
|
217
|
-
this.statusCode = statusCode;
|
|
218
|
-
this.responseBody = responseBody;
|
|
219
|
-
}
|
|
220
|
-
statusCode;
|
|
221
|
-
responseBody;
|
|
222
|
-
static isNotFound(err) {
|
|
223
|
-
return err instanceof _ApiError && err.statusCode === 404;
|
|
224
|
-
}
|
|
225
|
-
};
|
|
226
|
-
var ConflictError = class extends ApiError {
|
|
227
|
-
};
|
|
228
|
-
var BaseApiClient = class {
|
|
229
|
-
isConflict(_status, _body) {
|
|
230
|
-
return false;
|
|
231
|
-
}
|
|
232
|
-
async throwIfError(res) {
|
|
233
|
-
if (res.ok) return;
|
|
234
|
-
const body = await res.text();
|
|
235
|
-
if (this.isConflict(res.status, body)) throw new ConflictError(res.status, body, this.errorPrefix);
|
|
236
|
-
throw new ApiError(res.status, body, this.errorPrefix);
|
|
237
|
-
}
|
|
238
|
-
async post(path, body) {
|
|
239
|
-
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
240
|
-
method: "POST",
|
|
241
|
-
headers: this.headers(),
|
|
242
|
-
body: JSON.stringify(body)
|
|
243
|
-
});
|
|
244
|
-
await this.throwIfError(res);
|
|
245
|
-
return res.json();
|
|
246
|
-
}
|
|
247
|
-
async put(path, body) {
|
|
248
|
-
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
249
|
-
method: "PUT",
|
|
250
|
-
headers: this.headers(),
|
|
251
|
-
body: JSON.stringify(body)
|
|
252
|
-
});
|
|
253
|
-
await this.throwIfError(res);
|
|
254
|
-
return res.json();
|
|
255
|
-
}
|
|
256
|
-
async delete(path) {
|
|
257
|
-
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
258
|
-
method: "DELETE",
|
|
259
|
-
headers: this.headers()
|
|
260
|
-
});
|
|
261
|
-
await this.throwIfError(res);
|
|
262
|
-
}
|
|
263
|
-
async get(path) {
|
|
264
|
-
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
265
|
-
method: "GET",
|
|
266
|
-
headers: this.headers()
|
|
267
|
-
});
|
|
268
|
-
await this.throwIfError(res);
|
|
269
|
-
return res.json();
|
|
270
|
-
}
|
|
271
|
-
async getBuffer(path) {
|
|
272
|
-
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
273
|
-
method: "GET",
|
|
274
|
-
headers: this.headers()
|
|
275
|
-
});
|
|
276
|
-
await this.throwIfError(res);
|
|
277
|
-
return Buffer.from(await res.arrayBuffer());
|
|
278
|
-
}
|
|
279
|
-
async *sse(path, options) {
|
|
280
|
-
const controller = new AbortController();
|
|
281
|
-
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
282
|
-
method: "GET",
|
|
283
|
-
headers: { ...this.headers(), Accept: "text/event-stream", ...options?.headers },
|
|
284
|
-
signal: controller.signal
|
|
285
|
-
});
|
|
286
|
-
await this.throwIfError(res);
|
|
287
|
-
const reader = res.body.getReader();
|
|
288
|
-
const decoder = new TextDecoder();
|
|
289
|
-
let buffer = "";
|
|
290
|
-
try {
|
|
291
|
-
while (true) {
|
|
292
|
-
const { done, value } = await reader.read();
|
|
293
|
-
if (done) break;
|
|
294
|
-
buffer += decoder.decode(value, { stream: true });
|
|
295
|
-
let boundary = buffer.indexOf("\n\n");
|
|
296
|
-
while (boundary !== -1) {
|
|
297
|
-
const frame = buffer.slice(0, boundary);
|
|
298
|
-
buffer = buffer.slice(boundary + 2);
|
|
299
|
-
boundary = buffer.indexOf("\n\n");
|
|
300
|
-
const dataLines = [];
|
|
301
|
-
for (const line of frame.split("\n")) {
|
|
302
|
-
if (line.startsWith(":")) continue;
|
|
303
|
-
if (line.startsWith("event:") && line.slice(6).trim() === "heartbeat") {
|
|
304
|
-
dataLines.length = 0;
|
|
305
|
-
break;
|
|
306
|
-
}
|
|
307
|
-
if (line.startsWith("data:")) {
|
|
308
|
-
dataLines.push(line.slice(5).trimStart());
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
if (dataLines.length === 0) continue;
|
|
312
|
-
const json = dataLines.join("\n");
|
|
313
|
-
try {
|
|
314
|
-
yield JSON.parse(json);
|
|
315
|
-
} catch {
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
} finally {
|
|
320
|
-
try {
|
|
321
|
-
await reader.cancel();
|
|
322
|
-
} catch {
|
|
323
|
-
}
|
|
324
|
-
controller.abort();
|
|
325
|
-
reader.releaseLock();
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
async postFormData(path, formData) {
|
|
329
|
-
const { "Content-Type": _contentType, ...headers } = this.headers();
|
|
330
|
-
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
331
|
-
method: "POST",
|
|
332
|
-
headers,
|
|
333
|
-
body: formData
|
|
334
|
-
});
|
|
335
|
-
await this.throwIfError(res);
|
|
336
|
-
return res.json();
|
|
337
|
-
}
|
|
338
|
-
async getAllPaged(path) {
|
|
339
|
-
const all = [];
|
|
340
|
-
let cursor;
|
|
341
|
-
for (; ; ) {
|
|
342
|
-
const sep = path.includes("?") ? "&" : "?";
|
|
343
|
-
const param = this.paginationStrategy === "page" ? "page" : "after_id";
|
|
344
|
-
const url = cursor ? `${path}${sep}limit=100&${param}=${encodeURIComponent(cursor)}` : `${path}${sep}limit=100`;
|
|
345
|
-
const res = await this.get(url);
|
|
346
|
-
const data = res.data ?? [];
|
|
347
|
-
all.push(...data);
|
|
348
|
-
if (data.length === 0) break;
|
|
349
|
-
if (this.paginationStrategy === "page") {
|
|
350
|
-
if (!res.next_page) break;
|
|
351
|
-
cursor = res.next_page;
|
|
352
|
-
} else {
|
|
353
|
-
if (!res.has_more || !res.last_id) break;
|
|
354
|
-
cursor = res.last_id;
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
return all;
|
|
358
|
-
}
|
|
359
|
-
};
|
|
360
|
-
function toRemoteResource(res) {
|
|
361
|
-
return {
|
|
362
|
-
id: res.id,
|
|
363
|
-
type: res.type,
|
|
364
|
-
version: res.version
|
|
365
|
-
};
|
|
366
|
-
}
|
|
367
|
-
|
|
368
398
|
// src/internal/providers/memory-api.ts
|
|
369
399
|
function query(path, values) {
|
|
370
400
|
const params = new URLSearchParams();
|
|
@@ -849,8 +879,193 @@ function stripAgentsMetadata(value) {
|
|
|
849
879
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
850
880
|
}
|
|
851
881
|
|
|
882
|
+
// src/internal/utils/sandbox-mount.ts
|
|
883
|
+
var PROVIDER_MOUNT_PREFIXES = {
|
|
884
|
+
qoder: "/data",
|
|
885
|
+
claude: "/workspace",
|
|
886
|
+
bailian: "/mnt",
|
|
887
|
+
ark: "/mnt"
|
|
888
|
+
};
|
|
889
|
+
function joinAbsolute(prefix, sub) {
|
|
890
|
+
const left = prefix.replace(/\/+$/, "");
|
|
891
|
+
const right = sub.replace(/^\/+/, "");
|
|
892
|
+
return `${left}/${right}`;
|
|
893
|
+
}
|
|
894
|
+
function quoteShellWord(value) {
|
|
895
|
+
return `'${value.replaceAll("'", `'"'"'`)}'`;
|
|
896
|
+
}
|
|
897
|
+
function stripUrlQueryAndFragment(value) {
|
|
898
|
+
const queryIndex = value.indexOf("?");
|
|
899
|
+
const fragmentIndex = value.indexOf("#");
|
|
900
|
+
if (queryIndex === -1) {
|
|
901
|
+
return fragmentIndex === -1 ? value : value.slice(0, fragmentIndex);
|
|
902
|
+
}
|
|
903
|
+
if (fragmentIndex === -1) return value.slice(0, queryIndex);
|
|
904
|
+
return value.slice(0, Math.min(queryIndex, fragmentIndex));
|
|
905
|
+
}
|
|
906
|
+
function stripGitSuffix(value) {
|
|
907
|
+
return value.toLowerCase().endsWith(".git") ? value.slice(0, -4) : value;
|
|
908
|
+
}
|
|
909
|
+
function lastRemotePathSegment(value) {
|
|
910
|
+
const lastSlash = value.lastIndexOf("/");
|
|
911
|
+
const lastColon = value.lastIndexOf(":");
|
|
912
|
+
return value.slice(Math.max(lastSlash, lastColon) + 1).trim();
|
|
913
|
+
}
|
|
914
|
+
function providerMountPrefix(provider) {
|
|
915
|
+
return PROVIDER_MOUNT_PREFIXES[provider];
|
|
916
|
+
}
|
|
917
|
+
function resolveSandboxMountPath(provider, mountPath) {
|
|
918
|
+
const prefix = providerMountPrefix(provider);
|
|
919
|
+
if (!prefix) return mountPath;
|
|
920
|
+
if (mountPath === prefix || mountPath.startsWith(`${prefix}/`)) return mountPath;
|
|
921
|
+
if (mountPath.startsWith("/")) {
|
|
922
|
+
throw new UserError(`${provider} mount_path must start with '${prefix}/'; received '${mountPath}'.`);
|
|
923
|
+
}
|
|
924
|
+
return joinAbsolute(prefix, mountPath);
|
|
925
|
+
}
|
|
926
|
+
function resolveRepositoryMountPath(provider, resource) {
|
|
927
|
+
const prefix = providerMountPrefix(provider);
|
|
928
|
+
if (!prefix) throw new UserError(`Provider '${provider}' has no declared mount path prefix.`);
|
|
929
|
+
if (resource.mount_path) {
|
|
930
|
+
if (resource.mount_path !== prefix && !resource.mount_path.startsWith(`${prefix}/`)) {
|
|
931
|
+
throw new UserError(`${provider} Git repository Session resource mount_path must start with '${prefix}/'.`);
|
|
932
|
+
}
|
|
933
|
+
return resource.mount_path;
|
|
934
|
+
}
|
|
935
|
+
const repositoryName = stripGitSuffix(lastRemotePathSegment(stripUrlQueryAndFragment(resource.url)));
|
|
936
|
+
if (!repositoryName) {
|
|
937
|
+
throw new UserError(`Cannot derive a ${provider} Git repository mount path from URL '${resource.url}'.`);
|
|
938
|
+
}
|
|
939
|
+
return provider === "qoder" ? `${prefix}/workspace/${repositoryName}` : `${prefix}/${repositoryName}`;
|
|
940
|
+
}
|
|
941
|
+
function composeFileMountHint(files, provider) {
|
|
942
|
+
if (!files || files.length === 0) return "";
|
|
943
|
+
const lines = files.map((f) => `- ${resolveSandboxMountPath(provider, f.mount_path)}`);
|
|
944
|
+
return [
|
|
945
|
+
"The user uploaded files. They are available at the following sandbox paths:",
|
|
946
|
+
...lines,
|
|
947
|
+
"Read them from these paths when relevant."
|
|
948
|
+
].join("\n");
|
|
949
|
+
}
|
|
950
|
+
function prependFileHint(prompt, files, provider) {
|
|
951
|
+
const hint = composeFileMountHint(files, provider);
|
|
952
|
+
if (!hint) return prompt;
|
|
953
|
+
return `${hint}
|
|
954
|
+
|
|
955
|
+
${prompt}`;
|
|
956
|
+
}
|
|
957
|
+
var FILE_MENTION_START = "\u27E6file:";
|
|
958
|
+
var FILE_MENTION_END = "\u27E7";
|
|
959
|
+
function rewriteFileMentions(prompt, provider) {
|
|
960
|
+
let cursor = 0;
|
|
961
|
+
let rewritten = "";
|
|
962
|
+
while (cursor < prompt.length) {
|
|
963
|
+
const start = prompt.indexOf(FILE_MENTION_START, cursor);
|
|
964
|
+
if (start === -1) {
|
|
965
|
+
rewritten += prompt.slice(cursor);
|
|
966
|
+
break;
|
|
967
|
+
}
|
|
968
|
+
const mountPathStart = start + FILE_MENTION_START.length;
|
|
969
|
+
const end = prompt.indexOf(FILE_MENTION_END, mountPathStart);
|
|
970
|
+
if (end === -1) {
|
|
971
|
+
rewritten += prompt.slice(cursor);
|
|
972
|
+
break;
|
|
973
|
+
}
|
|
974
|
+
rewritten += prompt.slice(cursor, start);
|
|
975
|
+
rewritten += resolveSandboxMountPath(provider, prompt.slice(mountPathStart, end));
|
|
976
|
+
cursor = end + FILE_MENTION_END.length;
|
|
977
|
+
}
|
|
978
|
+
return rewritten;
|
|
979
|
+
}
|
|
980
|
+
function preparePromptForProvider(prompt, files, provider) {
|
|
981
|
+
return prependFileHint(rewriteFileMentions(prompt, provider), files, provider);
|
|
982
|
+
}
|
|
983
|
+
function prepareInitialSessionPrompt(prompt, bindings, provider) {
|
|
984
|
+
const prepared = preparePromptForProvider(prompt, bindings.files, provider);
|
|
985
|
+
const repositories = (bindings.resources ?? []).filter(
|
|
986
|
+
(resource) => resource.type === "github_repository"
|
|
987
|
+
);
|
|
988
|
+
if (repositories.length === 0) return prepared;
|
|
989
|
+
const paths = repositories.map((resource) => resolveRepositoryMountPath(provider, resource));
|
|
990
|
+
if (paths.length === 1) {
|
|
991
|
+
const path = paths[0];
|
|
992
|
+
return [
|
|
993
|
+
`The Git working tree for this task is mounted at \`${path}\`.`,
|
|
994
|
+
"Work only inside this directory unless the user explicitly requests otherwise.",
|
|
995
|
+
"Prefix every shell command with:",
|
|
996
|
+
`cd -- ${quoteShellWord(path)} &&`,
|
|
997
|
+
`Use absolute paths under \`${path}\` for non-shell file tools.`,
|
|
998
|
+
"",
|
|
999
|
+
prepared
|
|
1000
|
+
].join("\n");
|
|
1001
|
+
}
|
|
1002
|
+
const lines = ["Git working trees for this task are mounted at:", ...paths.map((path) => `- ${path}`)];
|
|
1003
|
+
lines.push("Choose the appropriate working tree for the task before inspecting or modifying files.");
|
|
1004
|
+
return `${lines.join("\n")}
|
|
1005
|
+
|
|
1006
|
+
${prepared}`;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
// src/internal/utils/tool-permissions.ts
|
|
1010
|
+
function canonicalToolName(name) {
|
|
1011
|
+
return name.trim().replace(/[^a-zA-Z0-9]+/g, "").toLowerCase();
|
|
1012
|
+
}
|
|
1013
|
+
function resolveBuiltinTools(tools, options = {}) {
|
|
1014
|
+
const permissionByName = /* @__PURE__ */ new Map();
|
|
1015
|
+
for (const [name, permission] of Object.entries(tools.permissions ?? {})) {
|
|
1016
|
+
permissionByName.set(canonicalToolName(name), permission);
|
|
1017
|
+
}
|
|
1018
|
+
const supportedByName = options.supportedWireNames ? new Map([...options.supportedWireNames].map((name) => [canonicalToolName(name), name])) : void 0;
|
|
1019
|
+
return tools.builtin.flatMap((configuredName) => {
|
|
1020
|
+
const candidate = options.toWireName?.(configuredName) ?? configuredName;
|
|
1021
|
+
const wireName = supportedByName?.get(canonicalToolName(candidate)) ?? (supportedByName ? void 0 : candidate);
|
|
1022
|
+
if (!wireName) return [];
|
|
1023
|
+
return [
|
|
1024
|
+
{
|
|
1025
|
+
configuredName,
|
|
1026
|
+
wireName,
|
|
1027
|
+
permission: permissionByName.get(canonicalToolName(configuredName)) ?? tools.default_permission ?? "allow"
|
|
1028
|
+
}
|
|
1029
|
+
];
|
|
1030
|
+
});
|
|
1031
|
+
}
|
|
1032
|
+
function toPermissionPolicy(permission) {
|
|
1033
|
+
return { type: permission === "ask" ? "always_ask" : "always_allow" };
|
|
1034
|
+
}
|
|
1035
|
+
function permissionOverridesFromWire(configs, toConfigName = (name) => name) {
|
|
1036
|
+
const permissions = {};
|
|
1037
|
+
for (const config of configs) {
|
|
1038
|
+
if (config.enabled === false) continue;
|
|
1039
|
+
const rawPolicy = config.permission_policy;
|
|
1040
|
+
const type = typeof rawPolicy === "string" ? rawPolicy : rawPolicy && typeof rawPolicy === "object" ? rawPolicy.type : void 0;
|
|
1041
|
+
if (type === "always_ask") permissions[toConfigName(config.name)] = "ask";
|
|
1042
|
+
else if (type === "always_allow") permissions[toConfigName(config.name)] = "allow";
|
|
1043
|
+
}
|
|
1044
|
+
return Object.keys(permissions).length ? permissions : void 0;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
// src/internal/providers/session-resource-mapper.ts
|
|
1048
|
+
function resolveGithubRepositoryMountPath(provider, resource) {
|
|
1049
|
+
return resolveRepositoryMountPath(provider, resource);
|
|
1050
|
+
}
|
|
1051
|
+
function mapGithubRepositorySessionResource(resource, options = {}) {
|
|
1052
|
+
const entry = {
|
|
1053
|
+
type: "github_repository",
|
|
1054
|
+
url: options.mapUrl?.(resource.url) ?? resource.url,
|
|
1055
|
+
authorization_token: resource.authorization_token
|
|
1056
|
+
};
|
|
1057
|
+
if (resource.checkout?.branch) entry.checkout = { type: "branch", name: resource.checkout.branch };
|
|
1058
|
+
else if (resource.checkout?.commit) entry.checkout = { type: "commit", sha: resource.checkout.commit };
|
|
1059
|
+
const mountPath = options.mapMountPath?.(resource) ?? resource.mount_path;
|
|
1060
|
+
if (mountPath) entry.mount_path = mountPath;
|
|
1061
|
+
return entry;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
852
1064
|
// src/internal/providers/claude/mapper.ts
|
|
853
1065
|
var CLAUDE_BUILTINS = /* @__PURE__ */ new Set(["read", "write", "edit", "bash", "glob", "grep", "web_search", "web_fetch"]);
|
|
1066
|
+
function normalizeGithubRepositoryUrlForClaude(url) {
|
|
1067
|
+
return url.replace(/\.git\/?$/, "");
|
|
1068
|
+
}
|
|
854
1069
|
function credToDecl(raw, vaultName) {
|
|
855
1070
|
const auth = raw.auth ?? {};
|
|
856
1071
|
const name = raw.display_name || raw.id || "credential";
|
|
@@ -921,6 +1136,7 @@ function agentToDecl(raw) {
|
|
|
921
1136
|
const skills = raw.skills;
|
|
922
1137
|
const multiagent = raw.multiagent;
|
|
923
1138
|
let builtinTools;
|
|
1139
|
+
let builtinPermissions;
|
|
924
1140
|
let allToolsEnabled = false;
|
|
925
1141
|
if (tools?.length) {
|
|
926
1142
|
const toolset = tools.find((t) => t.type === "agent_toolset_20260401");
|
|
@@ -929,6 +1145,7 @@ function agentToDecl(raw) {
|
|
|
929
1145
|
const configs = toolset.configs ?? [];
|
|
930
1146
|
if (configs.length > 0) {
|
|
931
1147
|
builtinTools = configs.filter((c) => c.enabled !== false).map((c) => c.name);
|
|
1148
|
+
builtinPermissions = permissionOverridesFromWire(configs);
|
|
932
1149
|
} else if (defaultConfig?.enabled) {
|
|
933
1150
|
allToolsEnabled = true;
|
|
934
1151
|
}
|
|
@@ -955,7 +1172,7 @@ function agentToDecl(raw) {
|
|
|
955
1172
|
}
|
|
956
1173
|
let toolsDecl;
|
|
957
1174
|
if (builtinTools?.length) {
|
|
958
|
-
toolsDecl = { builtin: builtinTools };
|
|
1175
|
+
toolsDecl = { builtin: builtinTools, permissions: builtinPermissions };
|
|
959
1176
|
} else if (allToolsEnabled) {
|
|
960
1177
|
toolsDecl = {
|
|
961
1178
|
builtin: ["read", "write", "edit", "bash", "glob", "grep", "web_search", "web_fetch"]
|
|
@@ -1015,16 +1232,11 @@ function mapAgent(name, decl, refs, version, projectName) {
|
|
|
1015
1232
|
body.metadata = decl.metadata;
|
|
1016
1233
|
}
|
|
1017
1234
|
if (decl.tools) {
|
|
1018
|
-
const toolConfigs = decl.tools
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
permission_policy: {
|
|
1024
|
-
type: permission === "ask" ? "always_ask" : "always_allow"
|
|
1025
|
-
}
|
|
1026
|
-
};
|
|
1027
|
-
});
|
|
1235
|
+
const toolConfigs = resolveBuiltinTools(decl.tools, { supportedWireNames: CLAUDE_BUILTINS }).map((tool) => ({
|
|
1236
|
+
name: tool.wireName,
|
|
1237
|
+
enabled: true,
|
|
1238
|
+
permission_policy: toPermissionPolicy(tool.permission)
|
|
1239
|
+
}));
|
|
1028
1240
|
body.tools = [
|
|
1029
1241
|
{
|
|
1030
1242
|
type: "agent_toolset_20260401",
|
|
@@ -1140,7 +1352,7 @@ function mapDeploymentResources(decl, refs, uploadedFiles) {
|
|
|
1140
1352
|
} else if (r.type === "github_repository") {
|
|
1141
1353
|
const entry = {
|
|
1142
1354
|
type: "github_repository",
|
|
1143
|
-
url: r.url
|
|
1355
|
+
url: normalizeGithubRepositoryUrlForClaude(r.url)
|
|
1144
1356
|
};
|
|
1145
1357
|
if (r.authorization_token) entry.authorization_token = r.authorization_token;
|
|
1146
1358
|
if (r.checkout?.branch) {
|
|
@@ -1269,8 +1481,16 @@ function mapSession(bindings) {
|
|
|
1269
1481
|
resources.push({
|
|
1270
1482
|
type: "file",
|
|
1271
1483
|
file_id: f.file_id,
|
|
1272
|
-
mount_path: f.mount_path
|
|
1484
|
+
mount_path: resolveSandboxMountPath("claude", f.mount_path)
|
|
1273
1485
|
});
|
|
1486
|
+
for (const resource of bindings.resources ?? []) {
|
|
1487
|
+
resources.push(
|
|
1488
|
+
mapGithubRepositorySessionResource(resource, {
|
|
1489
|
+
mapUrl: normalizeGithubRepositoryUrlForClaude,
|
|
1490
|
+
mapMountPath: (item) => resolveGithubRepositoryMountPath("claude", item)
|
|
1491
|
+
})
|
|
1492
|
+
);
|
|
1493
|
+
}
|
|
1274
1494
|
if (resources.length) body.resources = resources;
|
|
1275
1495
|
return body;
|
|
1276
1496
|
}
|
|
@@ -1749,6 +1969,7 @@ registerProvider({
|
|
|
1749
1969
|
name: "claude",
|
|
1750
1970
|
configSchema: claudeConfigSchema,
|
|
1751
1971
|
capabilities: CLAUDE_CAPABILITIES,
|
|
1972
|
+
features: { tool_permissions: true, session_resources: ["github_repository"] },
|
|
1752
1973
|
createAdapter: (config, projectName) => {
|
|
1753
1974
|
const c = config;
|
|
1754
1975
|
return new ClaudeAdapter(c.api_key, c.beta, projectName);
|
|
@@ -1757,7 +1978,7 @@ registerProvider({
|
|
|
1757
1978
|
|
|
1758
1979
|
// src/internal/providers/qoder/adapter.ts
|
|
1759
1980
|
import { readFileSync as readFileSync2 } from "fs";
|
|
1760
|
-
import { basename as
|
|
1981
|
+
import { basename as basename2, dirname as dirname2, resolve as resolve2 } from "path";
|
|
1761
1982
|
import JSZip2 from "jszip";
|
|
1762
1983
|
|
|
1763
1984
|
// src/internal/providers/qoder/client.ts
|
|
@@ -1782,57 +2003,6 @@ var QoderClient = class extends BaseApiClient {
|
|
|
1782
2003
|
}
|
|
1783
2004
|
};
|
|
1784
2005
|
|
|
1785
|
-
// src/internal/utils/sandbox-mount.ts
|
|
1786
|
-
var AGENTS_SESSION_PREFIX = "/mnt/session";
|
|
1787
|
-
function joinAbsolute(prefix, sub) {
|
|
1788
|
-
const left = prefix.replace(/\/+$/, "");
|
|
1789
|
-
const right = sub.replace(/^\/+/, "");
|
|
1790
|
-
return `${left}/${right}`;
|
|
1791
|
-
}
|
|
1792
|
-
function basename2(p) {
|
|
1793
|
-
const trimmed = p.replace(/\/+$/, "");
|
|
1794
|
-
const idx = trimmed.lastIndexOf("/");
|
|
1795
|
-
return idx === -1 ? trimmed : trimmed.slice(idx + 1);
|
|
1796
|
-
}
|
|
1797
|
-
function resolveSandboxMountPath(provider, mountPath) {
|
|
1798
|
-
switch (provider) {
|
|
1799
|
-
case "ark":
|
|
1800
|
-
case "bailian":
|
|
1801
|
-
case "claude":
|
|
1802
|
-
return joinAbsolute(AGENTS_SESSION_PREFIX, mountPath);
|
|
1803
|
-
case "qoder":
|
|
1804
|
-
return joinAbsolute("/data", basename2(mountPath));
|
|
1805
|
-
default:
|
|
1806
|
-
return mountPath;
|
|
1807
|
-
}
|
|
1808
|
-
}
|
|
1809
|
-
function composeFileMountHint(files, provider) {
|
|
1810
|
-
if (!files || files.length === 0) return "";
|
|
1811
|
-
const lines = files.map((f) => `- ${resolveSandboxMountPath(provider, f.mount_path)}`);
|
|
1812
|
-
return [
|
|
1813
|
-
"The user uploaded files. They are available at the following sandbox paths:",
|
|
1814
|
-
...lines,
|
|
1815
|
-
"Read them from these paths when relevant."
|
|
1816
|
-
].join("\n");
|
|
1817
|
-
}
|
|
1818
|
-
function prependFileHint(prompt, files, provider) {
|
|
1819
|
-
const hint = composeFileMountHint(files, provider);
|
|
1820
|
-
if (!hint) return prompt;
|
|
1821
|
-
return `${hint}
|
|
1822
|
-
|
|
1823
|
-
${prompt}`;
|
|
1824
|
-
}
|
|
1825
|
-
var FILE_MENTION_SENTINEL_RE = /\u27E6file:(.+?)\u27E7/g;
|
|
1826
|
-
function rewriteFileMentions(prompt, provider) {
|
|
1827
|
-
return prompt.replace(
|
|
1828
|
-
FILE_MENTION_SENTINEL_RE,
|
|
1829
|
-
(_match, mountPath) => resolveSandboxMountPath(provider, mountPath)
|
|
1830
|
-
);
|
|
1831
|
-
}
|
|
1832
|
-
function preparePromptForProvider(prompt, files, provider) {
|
|
1833
|
-
return prependFileHint(rewriteFileMentions(prompt, provider), files, provider);
|
|
1834
|
-
}
|
|
1835
|
-
|
|
1836
2006
|
// src/internal/providers/qoder/mapper.ts
|
|
1837
2007
|
function toPascalCase(name) {
|
|
1838
2008
|
return name.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[^a-zA-Z0-9]+/g, " ").trim().split(/\s+/).map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase()).join("");
|
|
@@ -1945,6 +2115,7 @@ function agentToDecl2(raw) {
|
|
|
1945
2115
|
const mcpServers = raw.mcp_servers;
|
|
1946
2116
|
const skills = raw.skills;
|
|
1947
2117
|
let builtinTools;
|
|
2118
|
+
let builtinPermissions;
|
|
1948
2119
|
if (tools?.length) {
|
|
1949
2120
|
const toolset = tools.find((t) => t.type === "agent_toolset_20260401");
|
|
1950
2121
|
if (toolset && Array.isArray(toolset.enabled_tools)) {
|
|
@@ -1952,6 +2123,7 @@ function agentToDecl2(raw) {
|
|
|
1952
2123
|
} else if (toolset) {
|
|
1953
2124
|
const configs = toolset.configs ?? [];
|
|
1954
2125
|
builtinTools = configs.filter((c) => c.enabled !== false).map((c) => normalizeToolNameFromQoder(c.name));
|
|
2126
|
+
builtinPermissions = permissionOverridesFromWire(configs, normalizeToolNameFromQoder);
|
|
1955
2127
|
}
|
|
1956
2128
|
}
|
|
1957
2129
|
let mcpServerDecls;
|
|
@@ -1973,7 +2145,7 @@ function agentToDecl2(raw) {
|
|
|
1973
2145
|
description: raw.description,
|
|
1974
2146
|
model: raw.model,
|
|
1975
2147
|
instructions: raw.system,
|
|
1976
|
-
tools: builtinTools?.length ? { builtin: builtinTools } : void 0,
|
|
2148
|
+
tools: builtinTools?.length ? { builtin: builtinTools, permissions: builtinPermissions } : void 0,
|
|
1977
2149
|
mcp_servers: mcpServerDecls,
|
|
1978
2150
|
skills: skillDecls,
|
|
1979
2151
|
metadata: stripAgentsMetadata(raw.metadata)
|
|
@@ -2106,11 +2278,14 @@ function mapAgent2(name, decl, refs, version, projectName) {
|
|
|
2106
2278
|
body.metadata = decl.metadata;
|
|
2107
2279
|
}
|
|
2108
2280
|
if (decl.tools) {
|
|
2109
|
-
const enabledTools = decl.tools.builtin.map((t) => normalizeToolNameForQoder(t));
|
|
2110
2281
|
body.tools = [
|
|
2111
2282
|
{
|
|
2112
2283
|
type: "agent_toolset_20260401",
|
|
2113
|
-
|
|
2284
|
+
configs: resolveBuiltinTools(decl.tools, { toWireName: normalizeToolNameForQoder }).map((tool) => ({
|
|
2285
|
+
name: tool.wireName,
|
|
2286
|
+
enabled: true,
|
|
2287
|
+
permission_policy: toPermissionPolicy(tool.permission)
|
|
2288
|
+
}))
|
|
2114
2289
|
}
|
|
2115
2290
|
];
|
|
2116
2291
|
} else {
|
|
@@ -2168,19 +2343,14 @@ function mapForwardTemplate(name, decl, refs, projectName) {
|
|
|
2168
2343
|
if (projectName) body.metadata = injectMetadata(decl.metadata, projectName, name);
|
|
2169
2344
|
else body.metadata = decl.metadata ?? {};
|
|
2170
2345
|
if (decl.tools) {
|
|
2171
|
-
const permissions = decl.tools.permissions ?? {};
|
|
2172
2346
|
body.tools = [
|
|
2173
2347
|
{
|
|
2174
2348
|
type: "agent_toolset_20260401",
|
|
2175
|
-
configs: decl.tools.
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
enabled: true,
|
|
2181
|
-
...policy ? { permission_policy: { type: policy === "ask" ? "always_ask" : "always_allow" } } : {}
|
|
2182
|
-
};
|
|
2183
|
-
})
|
|
2349
|
+
configs: resolveBuiltinTools(decl.tools, { toWireName: normalizeToolNameForQoder }).map((tool) => ({
|
|
2350
|
+
name: tool.wireName,
|
|
2351
|
+
enabled: true,
|
|
2352
|
+
permission_policy: toPermissionPolicy(tool.permission)
|
|
2353
|
+
}))
|
|
2184
2354
|
}
|
|
2185
2355
|
];
|
|
2186
2356
|
} else {
|
|
@@ -2236,6 +2406,7 @@ function toSessionEvent3(raw) {
|
|
|
2236
2406
|
const rawType = raw.type ?? "";
|
|
2237
2407
|
const type = QODER_EVENT_MAP[rawType] ?? "unknown";
|
|
2238
2408
|
const event = { type, raw_type: rawType, raw };
|
|
2409
|
+
if (typeof raw.id === "string") event.id = raw.id;
|
|
2239
2410
|
if (typeof raw.role === "string") event.role = raw.role;
|
|
2240
2411
|
if (type === "message") {
|
|
2241
2412
|
event.role = roleFromType2(rawType, raw.role);
|
|
@@ -2246,12 +2417,15 @@ function toSessionEvent3(raw) {
|
|
|
2246
2417
|
} else if (type === "tool_result") {
|
|
2247
2418
|
event.content = extractContentText2(raw);
|
|
2248
2419
|
} else if (type === "status") {
|
|
2420
|
+
const stopReason = extractStopReason2(raw.stop_reason);
|
|
2249
2421
|
if (rawType === "session.thread_status_idle") {
|
|
2250
2422
|
event.status = "running";
|
|
2423
|
+
} else if (rawType === "session.status_idle" && stopReason === "requires_action") {
|
|
2424
|
+
event.status = "running";
|
|
2251
2425
|
} else {
|
|
2252
2426
|
event.status = rawType.includes("idle") ? "idle" : rawType.includes("terminated") ? "terminated" : "running";
|
|
2253
2427
|
}
|
|
2254
|
-
event.stop_reason =
|
|
2428
|
+
event.stop_reason = stopReason;
|
|
2255
2429
|
} else if (type === "error") {
|
|
2256
2430
|
event.content = extractErrorMessage2(raw);
|
|
2257
2431
|
}
|
|
@@ -2313,6 +2487,13 @@ function mapSession2(bindings) {
|
|
|
2313
2487
|
for (const id of bindings.memory_store_ids) resources.push({ type: "memory_store", memory_store_id: id });
|
|
2314
2488
|
for (const f of bindings.files ?? [])
|
|
2315
2489
|
resources.push({ type: "file", file_id: f.file_id, mount_path: resolveSandboxMountPath("qoder", f.mount_path) });
|
|
2490
|
+
for (const resource of bindings.resources ?? []) {
|
|
2491
|
+
resources.push(
|
|
2492
|
+
mapGithubRepositorySessionResource(resource, {
|
|
2493
|
+
mapMountPath: (item) => resolveGithubRepositoryMountPath("qoder", item)
|
|
2494
|
+
})
|
|
2495
|
+
);
|
|
2496
|
+
}
|
|
2316
2497
|
if (resources.length) body.resources = resources;
|
|
2317
2498
|
return body;
|
|
2318
2499
|
}
|
|
@@ -2893,7 +3074,7 @@ var QoderAdapter = class _QoderAdapter {
|
|
|
2893
3074
|
const fullPath = resolve2(dirname2(basePath), source);
|
|
2894
3075
|
const content = readFileSync2(fullPath);
|
|
2895
3076
|
const formData = new FormData();
|
|
2896
|
-
formData.append("file", new File([new Uint8Array(content)],
|
|
3077
|
+
formData.append("file", new File([new Uint8Array(content)], basename2(fullPath)));
|
|
2897
3078
|
formData.append("purpose", "session_resource");
|
|
2898
3079
|
const res = await this.client.postFormData("/files", formData);
|
|
2899
3080
|
return res.file_id ?? res.id;
|
|
@@ -3066,7 +3247,7 @@ var QoderAdapter = class _QoderAdapter {
|
|
|
3066
3247
|
async uploadFile(filePath, options) {
|
|
3067
3248
|
const resolved = resolve2(filePath);
|
|
3068
3249
|
const content = readFileSync2(resolved);
|
|
3069
|
-
const fileName = options?.name ??
|
|
3250
|
+
const fileName = options?.name ?? basename2(resolved);
|
|
3070
3251
|
return this.uploadFileContent(new Uint8Array(content), fileName, {
|
|
3071
3252
|
purpose: options?.purpose
|
|
3072
3253
|
});
|
|
@@ -3191,6 +3372,7 @@ registerProvider({
|
|
|
3191
3372
|
name: "qoder",
|
|
3192
3373
|
configSchema: qoderConfigSchema,
|
|
3193
3374
|
capabilities: QODER_CAPABILITIES,
|
|
3375
|
+
features: { tool_permissions: true, session_resources: ["github_repository"] },
|
|
3194
3376
|
createAdapter: (config, projectName) => {
|
|
3195
3377
|
const c = config;
|
|
3196
3378
|
return new QoderAdapter(c.api_key, c.gateway, projectName, c.forward_gateway);
|
|
@@ -3199,7 +3381,7 @@ registerProvider({
|
|
|
3199
3381
|
|
|
3200
3382
|
// src/internal/providers/bailian/adapter.ts
|
|
3201
3383
|
import { readFileSync as readFileSync3 } from "fs";
|
|
3202
|
-
import { basename as
|
|
3384
|
+
import { basename as basename3, dirname as dirname3, extname, resolve as resolve3 } from "path";
|
|
3203
3385
|
import JSZip3 from "jszip";
|
|
3204
3386
|
|
|
3205
3387
|
// src/internal/providers/bailian/client.ts
|
|
@@ -3211,7 +3393,13 @@ var BailianClient = class extends BaseApiClient {
|
|
|
3211
3393
|
constructor(config) {
|
|
3212
3394
|
super();
|
|
3213
3395
|
this.apiKey = config.apiKey;
|
|
3214
|
-
|
|
3396
|
+
if (config.baseUrl) {
|
|
3397
|
+
this.baseUrl = config.baseUrl;
|
|
3398
|
+
} else if (config.workspaceId) {
|
|
3399
|
+
this.baseUrl = `https://${config.workspaceId}.cn-beijing.maas.aliyuncs.com/api/v1/agentstudio`;
|
|
3400
|
+
} else {
|
|
3401
|
+
throw new UserError("bailian provider requires either base_url or workspace_id");
|
|
3402
|
+
}
|
|
3215
3403
|
}
|
|
3216
3404
|
headers() {
|
|
3217
3405
|
return {
|
|
@@ -3393,8 +3581,8 @@ function mapAgent3(name, decl, refs, version, projectName, skillVersions) {
|
|
|
3393
3581
|
}
|
|
3394
3582
|
const BAILIAN_BUILTINS = /* @__PURE__ */ new Set(["bash", "read", "write", "edit", "glob", "grep", "download_file"]);
|
|
3395
3583
|
if (decl.tools) {
|
|
3396
|
-
const toolConfigs = decl.tools
|
|
3397
|
-
name:
|
|
3584
|
+
const toolConfigs = resolveBuiltinTools(decl.tools, { supportedWireNames: BAILIAN_BUILTINS }).map((tool) => ({
|
|
3585
|
+
name: tool.wireName,
|
|
3398
3586
|
enabled: true
|
|
3399
3587
|
}));
|
|
3400
3588
|
body.tools = [
|
|
@@ -3456,7 +3644,13 @@ function mapSession3(bindings) {
|
|
|
3456
3644
|
if (bindings.metadata) body.metadata = bindings.metadata;
|
|
3457
3645
|
if (bindings.vault_ids.length) body.vault_ids = bindings.vault_ids;
|
|
3458
3646
|
const resources = [];
|
|
3459
|
-
for (const f of bindings.files ?? [])
|
|
3647
|
+
for (const f of bindings.files ?? []) {
|
|
3648
|
+
resources.push({
|
|
3649
|
+
type: "file",
|
|
3650
|
+
file_id: f.file_id,
|
|
3651
|
+
mount_path: resolveSandboxMountPath("bailian", f.mount_path)
|
|
3652
|
+
});
|
|
3653
|
+
}
|
|
3460
3654
|
if (resources.length) body.resources = resources;
|
|
3461
3655
|
if (bindings.memory_store_ids.length) body.memory_store_ids = bindings.memory_store_ids;
|
|
3462
3656
|
return body;
|
|
@@ -3904,7 +4098,7 @@ var BailianAdapter = class _BailianAdapter {
|
|
|
3904
4098
|
const fullPath = resolve3(dirname3(basePath), source);
|
|
3905
4099
|
const content = readFileSync3(fullPath);
|
|
3906
4100
|
const formData = new FormData();
|
|
3907
|
-
formData.append("file", new File([new Uint8Array(content)],
|
|
4101
|
+
formData.append("file", new File([new Uint8Array(content)], basename3(fullPath)));
|
|
3908
4102
|
const res = await this.client.postFormData("/files", formData);
|
|
3909
4103
|
const fileId = res.id;
|
|
3910
4104
|
await this.waitForFileAvailable(fileId);
|
|
@@ -3969,7 +4163,7 @@ var BailianAdapter = class _BailianAdapter {
|
|
|
3969
4163
|
async uploadFile(filePath, options) {
|
|
3970
4164
|
const resolved = resolve3(filePath);
|
|
3971
4165
|
const content = readFileSync3(resolved);
|
|
3972
|
-
const fileName = options?.name ??
|
|
4166
|
+
const fileName = options?.name ?? basename3(resolved);
|
|
3973
4167
|
return this.uploadFileContent(new Uint8Array(content), fileName, {
|
|
3974
4168
|
purpose: options?.purpose
|
|
3975
4169
|
});
|
|
@@ -4105,8 +4299,10 @@ var BAILIAN_CAPABILITIES = {
|
|
|
4105
4299
|
import { z as z3 } from "zod";
|
|
4106
4300
|
var bailianConfigSchema = z3.object({
|
|
4107
4301
|
api_key: z3.string(),
|
|
4108
|
-
workspace_id: z3.string(),
|
|
4302
|
+
workspace_id: z3.string().optional(),
|
|
4109
4303
|
base_url: z3.string().optional()
|
|
4304
|
+
}).refine((config) => Boolean(config.workspace_id || config.base_url), {
|
|
4305
|
+
message: "either workspace_id or base_url is required"
|
|
4110
4306
|
});
|
|
4111
4307
|
|
|
4112
4308
|
// src/internal/providers/bailian/index.ts
|
|
@@ -4114,6 +4310,7 @@ registerProvider({
|
|
|
4114
4310
|
name: "bailian",
|
|
4115
4311
|
configSchema: bailianConfigSchema,
|
|
4116
4312
|
capabilities: BAILIAN_CAPABILITIES,
|
|
4313
|
+
features: { tool_permissions: false, session_resources: [] },
|
|
4117
4314
|
createAdapter: (config, projectName) => {
|
|
4118
4315
|
const c = config;
|
|
4119
4316
|
return new BailianAdapter(c.api_key, c.workspace_id, c.base_url, projectName);
|
|
@@ -4122,7 +4319,7 @@ registerProvider({
|
|
|
4122
4319
|
|
|
4123
4320
|
// src/internal/providers/ark/adapter.ts
|
|
4124
4321
|
import { readFileSync as readFileSync4 } from "fs";
|
|
4125
|
-
import { basename as
|
|
4322
|
+
import { basename as basename4, dirname as dirname4, resolve as resolve4 } from "path";
|
|
4126
4323
|
import JSZip4 from "jszip";
|
|
4127
4324
|
|
|
4128
4325
|
// src/internal/providers/resource-naming.ts
|
|
@@ -4247,6 +4444,7 @@ function agentToDecl4(raw) {
|
|
|
4247
4444
|
const skills = raw.skills;
|
|
4248
4445
|
const multiagent = raw.multiagent;
|
|
4249
4446
|
let builtinTools;
|
|
4447
|
+
let builtinPermissions;
|
|
4250
4448
|
let allToolsEnabled = false;
|
|
4251
4449
|
if (tools?.length) {
|
|
4252
4450
|
const toolset = tools.find((t) => t.type === "agent_toolset_20260701");
|
|
@@ -4255,6 +4453,7 @@ function agentToDecl4(raw) {
|
|
|
4255
4453
|
const configs = toolset.configs ?? [];
|
|
4256
4454
|
if (configs.length > 0) {
|
|
4257
4455
|
builtinTools = configs.filter((c) => c.enabled !== false).map((c) => c.name);
|
|
4456
|
+
builtinPermissions = permissionOverridesFromWire(configs);
|
|
4258
4457
|
} else if (defaultConfig?.enabled) {
|
|
4259
4458
|
allToolsEnabled = true;
|
|
4260
4459
|
}
|
|
@@ -4285,7 +4484,7 @@ function agentToDecl4(raw) {
|
|
|
4285
4484
|
}
|
|
4286
4485
|
let toolsDecl;
|
|
4287
4486
|
if (builtinTools?.length) {
|
|
4288
|
-
toolsDecl = { builtin: builtinTools };
|
|
4487
|
+
toolsDecl = { builtin: builtinTools, permissions: builtinPermissions };
|
|
4289
4488
|
} else if (allToolsEnabled) {
|
|
4290
4489
|
toolsDecl = {
|
|
4291
4490
|
builtin: ["read", "write", "edit", "bash", "glob", "grep", "web_search", "web_fetch"]
|
|
@@ -4346,16 +4545,11 @@ function mapAgent4(name, decl, refs, version, projectName) {
|
|
|
4346
4545
|
body.metadata = decl.metadata;
|
|
4347
4546
|
}
|
|
4348
4547
|
if (decl.tools) {
|
|
4349
|
-
const toolConfigs = decl.tools
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
permission_policy: {
|
|
4355
|
-
type: permission === "ask" ? "always_ask" : "always_allow"
|
|
4356
|
-
}
|
|
4357
|
-
};
|
|
4358
|
-
});
|
|
4548
|
+
const toolConfigs = resolveBuiltinTools(decl.tools, { supportedWireNames: ARK_BUILTINS }).map((tool) => ({
|
|
4549
|
+
name: tool.wireName,
|
|
4550
|
+
enabled: true,
|
|
4551
|
+
permission_policy: toPermissionPolicy(tool.permission)
|
|
4552
|
+
}));
|
|
4359
4553
|
body.tools = [
|
|
4360
4554
|
{
|
|
4361
4555
|
type: "agent_toolset_20260701",
|
|
@@ -4510,7 +4704,7 @@ function mapSession4(bindings) {
|
|
|
4510
4704
|
resources.push({
|
|
4511
4705
|
type: "file",
|
|
4512
4706
|
file_id: f.file_id,
|
|
4513
|
-
mount_path: f.mount_path
|
|
4707
|
+
mount_path: resolveSandboxMountPath("ark", f.mount_path)
|
|
4514
4708
|
});
|
|
4515
4709
|
if (resources.length) body.resources = resources;
|
|
4516
4710
|
return body;
|
|
@@ -4784,7 +4978,7 @@ var ArkAdapter = class _ArkAdapter {
|
|
|
4784
4978
|
const fullPath = resolve4(dirname4(basePath), source);
|
|
4785
4979
|
const content = readFileSync4(fullPath);
|
|
4786
4980
|
const formData = new FormData();
|
|
4787
|
-
formData.append("file", new File([new Uint8Array(content)],
|
|
4981
|
+
formData.append("file", new File([new Uint8Array(content)], basename4(fullPath)));
|
|
4788
4982
|
formData.append("purpose", "agent");
|
|
4789
4983
|
const res = await this.client.postFormData("/files", formData);
|
|
4790
4984
|
return res.file_id ?? res.id;
|
|
@@ -4833,7 +5027,7 @@ var ArkAdapter = class _ArkAdapter {
|
|
|
4833
5027
|
async uploadFile(filePath, options) {
|
|
4834
5028
|
const resolved = resolve4(filePath);
|
|
4835
5029
|
const content = readFileSync4(resolved);
|
|
4836
|
-
const fileName = options?.name ??
|
|
5030
|
+
const fileName = options?.name ?? basename4(resolved);
|
|
4837
5031
|
return this.uploadFileContent(new Uint8Array(content), fileName, {
|
|
4838
5032
|
purpose: options?.purpose
|
|
4839
5033
|
});
|
|
@@ -4914,6 +5108,7 @@ registerProvider({
|
|
|
4914
5108
|
name: "ark",
|
|
4915
5109
|
configSchema: arkConfigSchema,
|
|
4916
5110
|
capabilities: ARK_CAPABILITIES,
|
|
5111
|
+
features: { tool_permissions: true, session_resources: [] },
|
|
4917
5112
|
createAdapter: (config, projectName) => {
|
|
4918
5113
|
const c = config;
|
|
4919
5114
|
return new ArkAdapter(c.api_key, projectName);
|
|
@@ -5026,7 +5221,7 @@ async function resolveFileReferences(config, configPath) {
|
|
|
5026
5221
|
}
|
|
5027
5222
|
|
|
5028
5223
|
// src/internal/parser/resolve-project-config.ts
|
|
5029
|
-
import { basename as
|
|
5224
|
+
import { basename as basename5, dirname as dirname7, resolve as resolve7 } from "path";
|
|
5030
5225
|
|
|
5031
5226
|
// src/internal/parser/schema.ts
|
|
5032
5227
|
import { z as z5 } from "zod";
|
|
@@ -5171,8 +5366,32 @@ var mcpToolkitSchema = z5.object({
|
|
|
5171
5366
|
}));
|
|
5172
5367
|
var toolsSchema = z5.object({
|
|
5173
5368
|
builtin: z5.array(z5.string()),
|
|
5369
|
+
default_permission: z5.enum(["allow", "ask"]).optional(),
|
|
5174
5370
|
mcp: z5.array(mcpToolkitSchema).optional(),
|
|
5175
5371
|
permissions: z5.record(z5.string(), z5.enum(["allow", "ask"])).optional()
|
|
5372
|
+
}).superRefine((tools, ctx) => {
|
|
5373
|
+
const enabled = new Set(tools.builtin.map(canonicalToolName));
|
|
5374
|
+
const seen = /* @__PURE__ */ new Map();
|
|
5375
|
+
for (const key of Object.keys(tools.permissions ?? {})) {
|
|
5376
|
+
const canonical = canonicalToolName(key);
|
|
5377
|
+
const previous = seen.get(canonical);
|
|
5378
|
+
if (previous) {
|
|
5379
|
+
ctx.addIssue({
|
|
5380
|
+
code: "custom",
|
|
5381
|
+
path: ["permissions", key],
|
|
5382
|
+
message: `duplicates permission key '${previous}' after tool-name normalization`
|
|
5383
|
+
});
|
|
5384
|
+
} else {
|
|
5385
|
+
seen.set(canonical, key);
|
|
5386
|
+
}
|
|
5387
|
+
if (!enabled.has(canonical)) {
|
|
5388
|
+
ctx.addIssue({
|
|
5389
|
+
code: "custom",
|
|
5390
|
+
path: ["permissions", key],
|
|
5391
|
+
message: `references tool '${key}' which is not enabled in tools.builtin`
|
|
5392
|
+
});
|
|
5393
|
+
}
|
|
5394
|
+
}
|
|
5176
5395
|
});
|
|
5177
5396
|
var multiagentSchema = z5.object({
|
|
5178
5397
|
type: z5.literal("coordinator"),
|
|
@@ -5193,6 +5412,15 @@ var agentSkillRefSchema = z5.object({
|
|
|
5193
5412
|
var agentDeliverySchema = z5.object({
|
|
5194
5413
|
type: z5.enum(["managed", "forward"])
|
|
5195
5414
|
});
|
|
5415
|
+
var sessionGithubRepoResourceSchema = z5.object({
|
|
5416
|
+
type: z5.literal("github_repository"),
|
|
5417
|
+
url: z5.string().url(),
|
|
5418
|
+
checkout: z5.object({ branch: z5.string().min(1).optional(), commit: z5.string().min(1).optional() }).refine((value) => !(value.branch && value.commit), {
|
|
5419
|
+
message: "checkout accepts either branch or commit, not both"
|
|
5420
|
+
}).optional(),
|
|
5421
|
+
mount_path: z5.string().optional(),
|
|
5422
|
+
authorization_token: z5.string().min(1)
|
|
5423
|
+
});
|
|
5196
5424
|
var agentSchema = z5.object({
|
|
5197
5425
|
name: z5.string().optional(),
|
|
5198
5426
|
description: z5.string().optional(),
|
|
@@ -5206,6 +5434,7 @@ var agentSchema = z5.object({
|
|
|
5206
5434
|
skills: z5.array(z5.union([z5.string(), agentSkillRefSchema])).optional(),
|
|
5207
5435
|
vault: z5.string().optional(),
|
|
5208
5436
|
memory_stores: z5.array(z5.string()).optional(),
|
|
5437
|
+
resources: z5.array(sessionGithubRepoResourceSchema).optional(),
|
|
5209
5438
|
multiagent: multiagentSchema.optional(),
|
|
5210
5439
|
metadata: z5.record(z5.string(), z5.string()).optional(),
|
|
5211
5440
|
delivery: z5.record(z5.string(), agentDeliverySchema).optional()
|
|
@@ -5345,7 +5574,7 @@ async function loadConfig(filePath, resolveEnv = false) {
|
|
|
5345
5574
|
// src/internal/parser/resolve-project-config.ts
|
|
5346
5575
|
async function resolveProjectConfig(filePath, options = {}) {
|
|
5347
5576
|
const configPath = resolve7(filePath);
|
|
5348
|
-
const projectName = options.projectName ??
|
|
5577
|
+
const projectName = options.projectName ?? basename5(dirname7(configPath));
|
|
5349
5578
|
const { config: parsed, errors } = await loadConfig(configPath, options.resolveEnv ?? true);
|
|
5350
5579
|
if (errors.length > 0) {
|
|
5351
5580
|
throw new UserError(errors.join("\n"));
|
|
@@ -5757,7 +5986,7 @@ import { readFileSync as readFileSync7, statSync as statSync3 } from "fs";
|
|
|
5757
5986
|
import { dirname as dirname9, resolve as resolve10 } from "path";
|
|
5758
5987
|
async function resolveSkillFiles(decl, ctx) {
|
|
5759
5988
|
if (/^https?:\/\//i.test(decl.source)) {
|
|
5760
|
-
const res = await
|
|
5989
|
+
const res = await resolveFetch()(decl.source);
|
|
5761
5990
|
if (!res.ok) throw new Error(`skill source \u4E0B\u8F7D\u5931\u8D25\uFF1A${res.status} ${decl.source}`);
|
|
5762
5991
|
return extractSkillZipFiles(Buffer.from(await res.arrayBuffer()));
|
|
5763
5992
|
}
|
|
@@ -6605,6 +6834,43 @@ function collectProviderCapabilities(config, providers, diagnostics) {
|
|
|
6605
6834
|
for (const [name, agent] of Object.entries(config.agents ?? {})) {
|
|
6606
6835
|
if (agent.provider && agent.provider !== providerName) continue;
|
|
6607
6836
|
const delivery = agent.delivery?.[providerName]?.type ?? "managed";
|
|
6837
|
+
const address = {
|
|
6838
|
+
type: delivery === "forward" ? "template" : "agent",
|
|
6839
|
+
name,
|
|
6840
|
+
provider: providerName
|
|
6841
|
+
};
|
|
6842
|
+
const asksForApproval = agent.tools?.default_permission === "ask" || Object.values(agent.tools?.permissions ?? {}).some((permission) => permission === "ask");
|
|
6843
|
+
if (asksForApproval && !def.features.tool_permissions) {
|
|
6844
|
+
diagnostics.error(
|
|
6845
|
+
`${providerName}.agent.tool_permissions.unsupported`,
|
|
6846
|
+
`agent.${name}: provider '${providerName}' cannot enforce interactive tool permission 'ask'.`,
|
|
6847
|
+
address
|
|
6848
|
+
);
|
|
6849
|
+
}
|
|
6850
|
+
for (const resource of agent.resources ?? []) {
|
|
6851
|
+
if (!def.features.session_resources.includes(resource.type)) {
|
|
6852
|
+
diagnostics.error(
|
|
6853
|
+
`${providerName}.agent.session_resource.${resource.type}.unsupported`,
|
|
6854
|
+
`agent.${name}: provider '${providerName}' does not support Session resource type '${resource.type}'.`,
|
|
6855
|
+
address
|
|
6856
|
+
);
|
|
6857
|
+
}
|
|
6858
|
+
const mountPrefix = providerMountPrefix(providerName);
|
|
6859
|
+
if (mountPrefix && resource.mount_path && resource.mount_path !== mountPrefix && !resource.mount_path.startsWith(`${mountPrefix}/`)) {
|
|
6860
|
+
diagnostics.error(
|
|
6861
|
+
`${providerName}.agent.session_resource.mount_path.invalid`,
|
|
6862
|
+
`agent.${name}: ${providerName} Session resource mount_path must start with '${mountPrefix}/'.`,
|
|
6863
|
+
address
|
|
6864
|
+
);
|
|
6865
|
+
}
|
|
6866
|
+
}
|
|
6867
|
+
if (delivery === "forward" && agent.resources?.length) {
|
|
6868
|
+
diagnostics.error(
|
|
6869
|
+
`${providerName}.template.session_resources.unsupported`,
|
|
6870
|
+
`agent.${name}: Forward delivery cannot attach Agent Session resources; use managed delivery.`,
|
|
6871
|
+
address
|
|
6872
|
+
);
|
|
6873
|
+
}
|
|
6608
6874
|
if (delivery === "forward" && !isSupported(caps, "template")) {
|
|
6609
6875
|
diagnostics.error(
|
|
6610
6876
|
`${providerName}.agent.delivery.forward.unsupported`,
|
|
@@ -8107,7 +8373,21 @@ function buildSessionBindings(agentName, config, provider, state, options = {})
|
|
|
8107
8373
|
const available = Object.keys(config.agents ?? {}).join(", ");
|
|
8108
8374
|
throw new UserError(`Agent '${agentName}' not found in config. Available agents: ${available || "(none)"}`);
|
|
8109
8375
|
}
|
|
8376
|
+
const sessionResources = options.resources ?? agent.resources;
|
|
8377
|
+
const providerFeatures = getProvider(provider)?.features;
|
|
8378
|
+
for (const resource of sessionResources ?? []) {
|
|
8379
|
+
if (!providerFeatures?.session_resources.includes(resource.type)) {
|
|
8380
|
+
throw new UserError(
|
|
8381
|
+
`Provider '${provider}' does not support Session resource type '${resource.type}' for agent '${agentName}'.`
|
|
8382
|
+
);
|
|
8383
|
+
}
|
|
8384
|
+
}
|
|
8110
8385
|
if (resolveAgentMaterialization(provider, agent).resourceType === "template") {
|
|
8386
|
+
if (sessionResources?.length) {
|
|
8387
|
+
throw new UserError(
|
|
8388
|
+
`Forward session for '${agentName}' cannot attach Agent resources. Use managed delivery for GitHub repositories.`
|
|
8389
|
+
);
|
|
8390
|
+
}
|
|
8111
8391
|
const templateId = requireRef(state, { type: "template", name: agentName, provider });
|
|
8112
8392
|
const defaultIdentity = config.defaults?.identity;
|
|
8113
8393
|
const identityId = options.identityId ?? (defaultIdentity ? requireRef(state, { type: "identity", name: defaultIdentity, provider }) : void 0);
|
|
@@ -8165,6 +8445,7 @@ function buildSessionBindings(agentName, config, provider, state, options = {})
|
|
|
8165
8445
|
vault_ids: vaultIds,
|
|
8166
8446
|
memory_store_ids: memoryStoreIds,
|
|
8167
8447
|
files: (options.files ?? []).map((f) => ({ file_id: f.fileId, mount_path: f.mountPath })),
|
|
8448
|
+
resources: sessionResources,
|
|
8168
8449
|
title: options.title,
|
|
8169
8450
|
metadata: options.metadata
|
|
8170
8451
|
};
|
|
@@ -8534,6 +8815,7 @@ function toAgentSkillRef(skill) {
|
|
|
8534
8815
|
var TERMINAL_SESSION_STATUSES = /* @__PURE__ */ new Set(["idle", "completed", "failed", "terminated", "deleted"]);
|
|
8535
8816
|
var DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
8536
8817
|
var DEFAULT_POLL_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
8818
|
+
var POLL_INITIAL_INTERVAL_MS = 300;
|
|
8537
8819
|
function resolveAgentName(agents, agentName) {
|
|
8538
8820
|
if (agentName) return agentName;
|
|
8539
8821
|
const names = Object.keys(agents ?? {});
|
|
@@ -8564,6 +8846,7 @@ async function createSessionForAgent(ctx, options = {}) {
|
|
|
8564
8846
|
vaultIds: options.vaultIds,
|
|
8565
8847
|
memoryStores: options.memoryStores,
|
|
8566
8848
|
files: options.files,
|
|
8849
|
+
resources: options.resources,
|
|
8567
8850
|
title: options.title,
|
|
8568
8851
|
metadata: options.metadata
|
|
8569
8852
|
});
|
|
@@ -8582,6 +8865,7 @@ async function startSessionRun(ctx, prompt, options = {}) {
|
|
|
8582
8865
|
vaultIds: options.vaultIds,
|
|
8583
8866
|
memoryStores: options.memoryStores,
|
|
8584
8867
|
files: options.files,
|
|
8868
|
+
resources: options.resources,
|
|
8585
8869
|
title: options.title,
|
|
8586
8870
|
metadata: options.metadata
|
|
8587
8871
|
});
|
|
@@ -8590,7 +8874,7 @@ async function startSessionRun(ctx, prompt, options = {}) {
|
|
|
8590
8874
|
agentName,
|
|
8591
8875
|
provider,
|
|
8592
8876
|
session,
|
|
8593
|
-
events: streamMessageEvents(adapter2, session.id,
|
|
8877
|
+
events: streamMessageEvents(adapter2, session.id, prepareInitialSessionPrompt(prompt, bindings, provider))
|
|
8594
8878
|
};
|
|
8595
8879
|
}
|
|
8596
8880
|
function streamMessageEvents(adapter2, sessionId, message) {
|
|
@@ -8604,15 +8888,12 @@ async function sendSessionMessageStreaming(ctx, sessionId, message, options = {}
|
|
|
8604
8888
|
return streamMessageEvents(adapter2, sessionId, message);
|
|
8605
8889
|
}
|
|
8606
8890
|
async function startSessionRunPolling(ctx, prompt, options = {}) {
|
|
8607
|
-
const
|
|
8608
|
-
const
|
|
8609
|
-
const
|
|
8610
|
-
|
|
8611
|
-
|
|
8612
|
-
|
|
8613
|
-
);
|
|
8614
|
-
const collected = await sendSessionMessageAndCollectEvents(adapter2, run.session.id, hintedPrompt, options);
|
|
8615
|
-
return { ...run, ...collected };
|
|
8891
|
+
const { agentName, provider, adapter: adapter2 } = resolveSessionRuntime(ctx, options);
|
|
8892
|
+
const bindings = buildSessionBindings(agentName, ctx.config, provider, ctx.state, options);
|
|
8893
|
+
const session = await adapter2.createSession(bindings);
|
|
8894
|
+
const initialPrompt = prepareInitialSessionPrompt(prompt, bindings, provider);
|
|
8895
|
+
const collected = await sendSessionMessageAndCollectEvents(adapter2, session.id, initialPrompt, options);
|
|
8896
|
+
return { agentName, provider, session, ...collected };
|
|
8616
8897
|
}
|
|
8617
8898
|
async function sendSessionMessageAndCollectEvents(adapter2, sessionId, message, options = {}) {
|
|
8618
8899
|
const eventId = await adapter2.sendSessionMessage(sessionId, message);
|
|
@@ -8628,8 +8909,9 @@ async function sendSessionMessagePolling(ctx, sessionId, message, options = {})
|
|
|
8628
8909
|
}
|
|
8629
8910
|
async function collectEventsUntilTerminal(adapter2, sessionId, options = {}) {
|
|
8630
8911
|
const start = Date.now();
|
|
8631
|
-
const
|
|
8912
|
+
const maxPollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
8632
8913
|
const pollTimeoutMs = options.pollTimeoutMs ?? DEFAULT_POLL_TIMEOUT_MS;
|
|
8914
|
+
let currentIntervalMs = Math.min(POLL_INITIAL_INTERVAL_MS, maxPollIntervalMs);
|
|
8633
8915
|
let terminalStatus = "idle";
|
|
8634
8916
|
let result;
|
|
8635
8917
|
if (options.afterId) {
|
|
@@ -8646,7 +8928,8 @@ async function collectEventsUntilTerminal(adapter2, sessionId, options = {}) {
|
|
|
8646
8928
|
terminalStatus = terminalEvent.status;
|
|
8647
8929
|
break;
|
|
8648
8930
|
}
|
|
8649
|
-
await delay(
|
|
8931
|
+
await delay(currentIntervalMs);
|
|
8932
|
+
currentIntervalMs = Math.min(currentIntervalMs * 2, maxPollIntervalMs);
|
|
8650
8933
|
}
|
|
8651
8934
|
} else {
|
|
8652
8935
|
while (true) {
|
|
@@ -8656,7 +8939,8 @@ async function collectEventsUntilTerminal(adapter2, sessionId, options = {}) {
|
|
|
8656
8939
|
terminalStatus = session.status;
|
|
8657
8940
|
break;
|
|
8658
8941
|
}
|
|
8659
|
-
await delay(
|
|
8942
|
+
await delay(currentIntervalMs);
|
|
8943
|
+
currentIntervalMs = Math.min(currentIntervalMs * 2, maxPollIntervalMs);
|
|
8660
8944
|
}
|
|
8661
8945
|
result = await adapter2.listSessionEvents(sessionId, { limit: 100 });
|
|
8662
8946
|
}
|
|
@@ -8804,7 +9088,28 @@ function buildAgentNameByRemoteId(ctx, provider) {
|
|
|
8804
9088
|
}
|
|
8805
9089
|
async function* streamWithResume(adapter2, sessionId, message) {
|
|
8806
9090
|
const eventId = await adapter2.sendSessionMessage(sessionId, message);
|
|
8807
|
-
|
|
9091
|
+
let lastEventId = eventId;
|
|
9092
|
+
let reachedTerminal = false;
|
|
9093
|
+
let reconnectIntervalMs = POLL_INITIAL_INTERVAL_MS;
|
|
9094
|
+
const start = Date.now();
|
|
9095
|
+
while (!reachedTerminal) {
|
|
9096
|
+
assertNotTimedOut(start, DEFAULT_POLL_TIMEOUT_MS);
|
|
9097
|
+
for await (const event of adapter2.streamSessionEvents(
|
|
9098
|
+
sessionId,
|
|
9099
|
+
lastEventId ? { after_id: lastEventId } : void 0
|
|
9100
|
+
)) {
|
|
9101
|
+
if (event.id) lastEventId = event.id;
|
|
9102
|
+
yield event;
|
|
9103
|
+
if (event.type === "status" && isTerminalSessionStatus(event.status)) {
|
|
9104
|
+
reachedTerminal = true;
|
|
9105
|
+
break;
|
|
9106
|
+
}
|
|
9107
|
+
}
|
|
9108
|
+
if (!reachedTerminal) {
|
|
9109
|
+
await delay(reconnectIntervalMs);
|
|
9110
|
+
reconnectIntervalMs = Math.min(reconnectIntervalMs * 2, DEFAULT_POLL_INTERVAL_MS);
|
|
9111
|
+
}
|
|
9112
|
+
}
|
|
8808
9113
|
}
|
|
8809
9114
|
async function* streamConnectBeforeSend(adapter2, sessionId, message) {
|
|
8810
9115
|
const iterator = adapter2.streamSessionEvents(sessionId)[Symbol.asyncIterator]();
|
|
@@ -8861,7 +9166,11 @@ function resolveActiveProvider() {
|
|
|
8861
9166
|
}
|
|
8862
9167
|
function areRuntimeCredentialsReady() {
|
|
8863
9168
|
const provider = resolveActiveProvider();
|
|
8864
|
-
return AGENTS_PROVIDER_FIELDS[provider].every((field) =>
|
|
9169
|
+
return AGENTS_PROVIDER_FIELDS[provider].every((field) => {
|
|
9170
|
+
if (process.env[field.key]?.trim()) return true;
|
|
9171
|
+
if (field.key === "BAILIAN_WORKSPACE_ID") return Boolean(process.env.BAILIAN_BASE_URL?.trim());
|
|
9172
|
+
return false;
|
|
9173
|
+
});
|
|
8865
9174
|
}
|
|
8866
9175
|
function isProvider(value) {
|
|
8867
9176
|
return AGENTS_CONFIG_PROVIDERS.includes(value);
|
|
@@ -9458,9 +9767,11 @@ export {
|
|
|
9458
9767
|
AgentSyncRunSchema,
|
|
9459
9768
|
AgentSyncStatusSchema,
|
|
9460
9769
|
AgentWithReadinessSchema,
|
|
9770
|
+
ApiError,
|
|
9461
9771
|
CloudAgentSchema,
|
|
9462
9772
|
CloudEnvironmentSchema,
|
|
9463
9773
|
CloudVaultSchema,
|
|
9774
|
+
ConflictError,
|
|
9464
9775
|
CreateSessionRequestSchema,
|
|
9465
9776
|
CreateSessionResponseSchema,
|
|
9466
9777
|
DiagnosticSchema,
|
|
@@ -9551,6 +9862,7 @@ export {
|
|
|
9551
9862
|
pauseDeploymentForContext,
|
|
9552
9863
|
planDestroyProjectContext,
|
|
9553
9864
|
planProjectContext,
|
|
9865
|
+
prepareInitialSessionPrompt,
|
|
9554
9866
|
preparePromptForProvider,
|
|
9555
9867
|
prependFileHint,
|
|
9556
9868
|
providerConfigPath,
|
|
@@ -9560,12 +9872,14 @@ export {
|
|
|
9560
9872
|
resolveProjectConfig,
|
|
9561
9873
|
resolveProjectConfigFromObject,
|
|
9562
9874
|
resolveProviderConfigFromEnv,
|
|
9875
|
+
resolveRepositoryMountPath,
|
|
9563
9876
|
resolveSessionProvider,
|
|
9564
9877
|
resolveSyncProvider,
|
|
9565
9878
|
rewriteFileMentions,
|
|
9566
9879
|
runDeploymentForContext,
|
|
9567
9880
|
sendSessionMessagePolling,
|
|
9568
9881
|
sendSessionMessageStreaming,
|
|
9882
|
+
setDefaultFetch,
|
|
9569
9883
|
startSessionRun,
|
|
9570
9884
|
startSessionRunPolling,
|
|
9571
9885
|
streamSessionEvents,
|