@cadraos/sdk 0.3.14-p46.4 → 0.3.15
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/README.md +104 -53
- package/dist/ai-functions/react/index.cjs +176 -0
- package/dist/ai-functions/react/index.cjs.map +1 -0
- package/dist/ai-functions/react/index.d.cts +129 -0
- package/dist/ai-functions/react/index.d.ts +129 -0
- package/dist/ai-functions/react/index.js +153 -0
- package/dist/ai-functions/react/index.js.map +1 -0
- package/dist/ai-functions/server/index.cjs +296 -0
- package/dist/ai-functions/server/index.cjs.map +1 -0
- package/dist/ai-functions/server/index.d.cts +334 -0
- package/dist/ai-functions/server/index.d.ts +334 -0
- package/dist/ai-functions/server/index.js +284 -0
- package/dist/ai-functions/server/index.js.map +1 -0
- package/dist/chat/index.cjs +303 -17
- package/dist/chat/index.cjs.map +1 -1
- package/dist/chat/index.d.cts +211 -0
- package/dist/chat/index.d.ts +211 -0
- package/dist/chat/index.js +303 -17
- package/dist/chat/index.js.map +1 -1
- package/dist/index.cjs +225 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +279 -1
- package/dist/index.d.ts +279 -1
- package/dist/index.js +219 -4
- package/dist/index.js.map +1 -1
- package/dist/kanban/index.cjs +218 -3
- package/dist/kanban/index.cjs.map +1 -1
- package/dist/kanban/index.d.cts +211 -0
- package/dist/kanban/index.d.ts +211 -0
- package/dist/kanban/index.js +218 -3
- package/dist/kanban/index.js.map +1 -1
- package/dist/teams/index.cjs +218 -3
- package/dist/teams/index.cjs.map +1 -1
- package/dist/teams/index.d.cts +211 -0
- package/dist/teams/index.d.ts +211 -0
- package/dist/teams/index.js +218 -3
- package/dist/teams/index.js.map +1 -1
- package/package.json +21 -1
package/dist/chat/index.js
CHANGED
|
@@ -68,6 +68,14 @@ var CadraError = class extends Error {
|
|
|
68
68
|
details;
|
|
69
69
|
/** Request ID from server (for debugging) */
|
|
70
70
|
requestId;
|
|
71
|
+
/**
|
|
72
|
+
* The server's own `error.code` exactly as sent on the wire (e.g.
|
|
73
|
+
* `FUNCTION_NOT_PUBLISHED`, `DUPLICATE_REQUEST`, `VARIABLE_TYPE`).
|
|
74
|
+
* Populated by `parseApiError` for EVERY status. `code` keeps its historic
|
|
75
|
+
* per-class values (`conflict`, `server_error`, `validation_error`, …) for
|
|
76
|
+
* compatibility; branch on `serverCode` when you need the precise reason.
|
|
77
|
+
*/
|
|
78
|
+
serverCode;
|
|
71
79
|
constructor(message, code, status, details, requestId) {
|
|
72
80
|
super(message);
|
|
73
81
|
this.name = "CadraError";
|
|
@@ -145,6 +153,12 @@ function parseApiError(status, body, requestId) {
|
|
|
145
153
|
const message = errorBody?.error?.message ?? "An error occurred";
|
|
146
154
|
const code = errorBody?.error?.code ?? "unknown_error";
|
|
147
155
|
const details = errorBody?.error?.details;
|
|
156
|
+
const serverCode = typeof errorBody?.error?.code === "string" ? errorBody.error.code : void 0;
|
|
157
|
+
const error = buildApiError(status, message, code, details, requestId);
|
|
158
|
+
if (serverCode !== void 0) error.serverCode = serverCode;
|
|
159
|
+
return error;
|
|
160
|
+
}
|
|
161
|
+
function buildApiError(status, message, code, details, requestId) {
|
|
148
162
|
switch (status) {
|
|
149
163
|
case 400:
|
|
150
164
|
case 422: {
|
|
@@ -180,6 +194,42 @@ function parseApiError(status, body, requestId) {
|
|
|
180
194
|
}
|
|
181
195
|
}
|
|
182
196
|
|
|
197
|
+
// src/errors/ai-function-errors.ts
|
|
198
|
+
var AiFunctionDuplicateError = class extends ConflictError {
|
|
199
|
+
/** The existing run's execution id. */
|
|
200
|
+
executionId;
|
|
201
|
+
/** The existing run's status (`running`, a terminal status, or `abandoned`). */
|
|
202
|
+
runStatus;
|
|
203
|
+
constructor(message, details, requestId) {
|
|
204
|
+
super(message, details, requestId);
|
|
205
|
+
this.name = "AiFunctionDuplicateError";
|
|
206
|
+
this.serverCode = "DUPLICATE_REQUEST";
|
|
207
|
+
this.executionId = typeof details?.executionId === "string" ? details.executionId : void 0;
|
|
208
|
+
this.runStatus = typeof details?.status === "string" ? details.status : void 0;
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
var AiFunctionChargedError = class extends CadraError {
|
|
212
|
+
constructor(source) {
|
|
213
|
+
super(source.message, source.code, source.status, source.details, source.requestId);
|
|
214
|
+
this.name = "AiFunctionChargedError";
|
|
215
|
+
this.serverCode = source.serverCode;
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
var AiFunctionParameterError = class extends ValidationError {
|
|
219
|
+
functionKey;
|
|
220
|
+
issues;
|
|
221
|
+
constructor(functionKey, issues) {
|
|
222
|
+
super(
|
|
223
|
+
`Invalid parameters for AI function "${functionKey}": ` + issues.map((i) => `${i.name} (${i.code})`).join(", "),
|
|
224
|
+
issues.map((i) => ({ field: i.name, message: i.code })),
|
|
225
|
+
{ functionKey, issues }
|
|
226
|
+
);
|
|
227
|
+
this.name = "AiFunctionParameterError";
|
|
228
|
+
this.functionKey = functionKey;
|
|
229
|
+
this.issues = issues;
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
|
|
183
233
|
// src/utils/retry.ts
|
|
184
234
|
var DEFAULT_RETRY_CONFIG = {
|
|
185
235
|
maxRetries: 3,
|
|
@@ -244,6 +294,10 @@ var HttpClient = class {
|
|
|
244
294
|
constructor(config) {
|
|
245
295
|
this.config = config;
|
|
246
296
|
}
|
|
297
|
+
/** The client-wide request timeout (ms) this client was configured with. */
|
|
298
|
+
get timeoutMs() {
|
|
299
|
+
return this.config.timeout;
|
|
300
|
+
}
|
|
247
301
|
/**
|
|
248
302
|
* Get authorization header value
|
|
249
303
|
*/
|
|
@@ -298,7 +352,8 @@ var HttpClient = class {
|
|
|
298
352
|
headers["Idempotency-Key"] = options.idempotencyKey;
|
|
299
353
|
}
|
|
300
354
|
const controller = new AbortController();
|
|
301
|
-
const
|
|
355
|
+
const timeoutMs = options.timeoutMs ?? this.config.timeout;
|
|
356
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
302
357
|
try {
|
|
303
358
|
const doFetch = this.config.fetch ?? fetch;
|
|
304
359
|
const response = await doFetch(url, {
|
|
@@ -334,7 +389,7 @@ var HttpClient = class {
|
|
|
334
389
|
} catch (error) {
|
|
335
390
|
clearTimeout(timeoutId);
|
|
336
391
|
if (error instanceof Error && error.name === "AbortError") {
|
|
337
|
-
throw new TimeoutError(`Request timed out after ${this.config.timeout}ms`);
|
|
392
|
+
throw new TimeoutError(`Request timed out after ${options.timeoutMs ?? this.config.timeout}ms`);
|
|
338
393
|
}
|
|
339
394
|
if (error instanceof TypeError && error.message.includes("fetch")) {
|
|
340
395
|
throw new NetworkError(`Network error: ${error.message}`);
|
|
@@ -366,7 +421,8 @@ var HttpClient = class {
|
|
|
366
421
|
path,
|
|
367
422
|
body,
|
|
368
423
|
idempotencyKey: options?.idempotencyKey,
|
|
369
|
-
skipRetry: options?.skipRetry
|
|
424
|
+
skipRetry: options?.skipRetry,
|
|
425
|
+
timeoutMs: options?.timeoutMs
|
|
370
426
|
});
|
|
371
427
|
}
|
|
372
428
|
/**
|
|
@@ -1125,6 +1181,10 @@ var ExecutionStreamControllerImpl = class {
|
|
|
1125
1181
|
toolName,
|
|
1126
1182
|
result: data.result,
|
|
1127
1183
|
durationMs: data.durationMs ?? 0,
|
|
1184
|
+
// CAD-243: pass the producer's failure verdict through.
|
|
1185
|
+
...data.isError === true ? { isError: true } : {},
|
|
1186
|
+
...typeof data.status === "string" ? { status: data.status } : {},
|
|
1187
|
+
...typeof data.error === "string" ? { error: data.error } : {},
|
|
1128
1188
|
forwardedFrom: event.data._forwardedFrom,
|
|
1129
1189
|
// CAD-87 S1-001 EventIdentity → (execId, seq) reducer dedup (S1-003).
|
|
1130
1190
|
sourceExecutionId: data.sourceExecutionId ?? data.executionId,
|
|
@@ -3363,6 +3423,156 @@ var RemoteRunnersAPI = class extends BaseResourceAPI {
|
|
|
3363
3423
|
}
|
|
3364
3424
|
};
|
|
3365
3425
|
|
|
3426
|
+
// src/resources/ai-functions.ts
|
|
3427
|
+
var AI_FUNCTION_RUN_TIMEOUT_MS = 31e4;
|
|
3428
|
+
var AI_FUNCTION_DESCRIPTOR_TTL_MS = 6e4;
|
|
3429
|
+
function checkAiFunctionParameters(parameters, variables) {
|
|
3430
|
+
const issues = [];
|
|
3431
|
+
const declared = /* @__PURE__ */ new Set();
|
|
3432
|
+
for (const p of parameters) {
|
|
3433
|
+
declared.add(p.name);
|
|
3434
|
+
const has = Object.prototype.hasOwnProperty.call(variables, p.name);
|
|
3435
|
+
const value = has ? variables[p.name] : void 0;
|
|
3436
|
+
if (value === void 0 || value === null) {
|
|
3437
|
+
if (p.required) issues.push({ name: p.name, code: "missing" });
|
|
3438
|
+
continue;
|
|
3439
|
+
}
|
|
3440
|
+
switch (p.type) {
|
|
3441
|
+
case "number":
|
|
3442
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
3443
|
+
issues.push({ name: p.name, code: "type" });
|
|
3444
|
+
}
|
|
3445
|
+
break;
|
|
3446
|
+
case "boolean":
|
|
3447
|
+
if (typeof value !== "boolean") issues.push({ name: p.name, code: "type" });
|
|
3448
|
+
break;
|
|
3449
|
+
case "enum":
|
|
3450
|
+
if (typeof value !== "string") issues.push({ name: p.name, code: "type" });
|
|
3451
|
+
else if (p.options && !p.options.includes(value)) {
|
|
3452
|
+
issues.push({ name: p.name, code: "option" });
|
|
3453
|
+
}
|
|
3454
|
+
break;
|
|
3455
|
+
case "string":
|
|
3456
|
+
case "text":
|
|
3457
|
+
if (typeof value !== "string") issues.push({ name: p.name, code: "type" });
|
|
3458
|
+
else if (typeof p.maxLength === "number" && value.length > p.maxLength) {
|
|
3459
|
+
issues.push({ name: p.name, code: "too_long" });
|
|
3460
|
+
}
|
|
3461
|
+
break;
|
|
3462
|
+
case "image":
|
|
3463
|
+
if (typeof value !== "string") issues.push({ name: p.name, code: "type" });
|
|
3464
|
+
break;
|
|
3465
|
+
}
|
|
3466
|
+
}
|
|
3467
|
+
for (const name of Object.keys(variables)) {
|
|
3468
|
+
if (!declared.has(name)) issues.push({ name, code: "unknown" });
|
|
3469
|
+
}
|
|
3470
|
+
return issues;
|
|
3471
|
+
}
|
|
3472
|
+
var AiFunctionsAPI = class extends BaseResourceAPI {
|
|
3473
|
+
descriptorCache = /* @__PURE__ */ new Map();
|
|
3474
|
+
constructor(http) {
|
|
3475
|
+
super(http, "/api/v1/ai-functions");
|
|
3476
|
+
}
|
|
3477
|
+
/**
|
|
3478
|
+
* List the functions this org can call — the index (D27a). Each entry carries
|
|
3479
|
+
* the live version's typed parameters; never prompt text.
|
|
3480
|
+
*/
|
|
3481
|
+
async list() {
|
|
3482
|
+
const data = await this.httpGet("");
|
|
3483
|
+
const functions = Array.isArray(data) ? data : data?.functions ?? [];
|
|
3484
|
+
for (const d of functions) this.cacheDescriptor(d);
|
|
3485
|
+
return functions;
|
|
3486
|
+
}
|
|
3487
|
+
/**
|
|
3488
|
+
* Get one function's descriptor by key (D27a).
|
|
3489
|
+
* `NotFoundError` (`FUNCTION_NOT_FOUND`) / `ConflictError` (`FUNCTION_NOT_PUBLISHED`).
|
|
3490
|
+
*/
|
|
3491
|
+
async get(functionKey) {
|
|
3492
|
+
const data = await this.httpGet(
|
|
3493
|
+
`/${encodeURIComponent(functionKey)}`
|
|
3494
|
+
);
|
|
3495
|
+
const descriptor = data && typeof data === "object" && "function" in data && !("functionKey" in data) ? data.function : data;
|
|
3496
|
+
this.cacheDescriptor(descriptor, functionKey);
|
|
3497
|
+
return descriptor;
|
|
3498
|
+
}
|
|
3499
|
+
/**
|
|
3500
|
+
* Read one of this org's own runs (safe projection, §6.5).
|
|
3501
|
+
*/
|
|
3502
|
+
async getRun(executionId) {
|
|
3503
|
+
return this.httpGet(`/runs/${encodeURIComponent(executionId)}`);
|
|
3504
|
+
}
|
|
3505
|
+
/** Forget cached descriptors (one key, or all). */
|
|
3506
|
+
clearDescriptorCache(functionKey) {
|
|
3507
|
+
if (functionKey) this.descriptorCache.delete(functionKey);
|
|
3508
|
+
else this.descriptorCache.clear();
|
|
3509
|
+
}
|
|
3510
|
+
async run(refOrKey, parametersOrOptions, shorthandOpts) {
|
|
3511
|
+
let ref;
|
|
3512
|
+
let options;
|
|
3513
|
+
if (typeof refOrKey === "string") {
|
|
3514
|
+
ref = { functionKey: refOrKey };
|
|
3515
|
+
options = { ...shorthandOpts ?? {}, variables: parametersOrOptions };
|
|
3516
|
+
} else {
|
|
3517
|
+
ref = refOrKey;
|
|
3518
|
+
options = parametersOrOptions;
|
|
3519
|
+
}
|
|
3520
|
+
const variables = options.variables ?? {};
|
|
3521
|
+
const functionKey = "functionKey" in ref ? ref.functionKey : void 0;
|
|
3522
|
+
const shouldCheck = functionKey !== void 0 && options.version === void 0 && options.validate !== false;
|
|
3523
|
+
if (shouldCheck) {
|
|
3524
|
+
const descriptor = await this.getCachedDescriptor(functionKey);
|
|
3525
|
+
const issues = checkAiFunctionParameters(descriptor.parameters, variables);
|
|
3526
|
+
if (issues.length > 0) {
|
|
3527
|
+
throw new AiFunctionParameterError(functionKey, issues);
|
|
3528
|
+
}
|
|
3529
|
+
}
|
|
3530
|
+
const body = {
|
|
3531
|
+
ref,
|
|
3532
|
+
variables,
|
|
3533
|
+
version: options.version,
|
|
3534
|
+
idempotencyKey: options.idempotencyKey ?? generateExecutionId(),
|
|
3535
|
+
params: options.params
|
|
3536
|
+
};
|
|
3537
|
+
try {
|
|
3538
|
+
return await this.httpPost("/run", body, {
|
|
3539
|
+
skipRetry: true,
|
|
3540
|
+
timeoutMs: Math.max(AI_FUNCTION_RUN_TIMEOUT_MS, this.http.timeoutMs ?? 0)
|
|
3541
|
+
});
|
|
3542
|
+
} catch (error) {
|
|
3543
|
+
throw this.mapRunError(error, functionKey);
|
|
3544
|
+
}
|
|
3545
|
+
}
|
|
3546
|
+
// ── internals ──────────────────────────────────────────────────────────────
|
|
3547
|
+
cacheDescriptor(descriptor, key) {
|
|
3548
|
+
if (!descriptor || typeof descriptor !== "object") return;
|
|
3549
|
+
const cacheKey = key ?? descriptor.functionKey;
|
|
3550
|
+
if (!cacheKey) return;
|
|
3551
|
+
this.descriptorCache.set(cacheKey, {
|
|
3552
|
+
descriptor,
|
|
3553
|
+
expiresAt: Date.now() + AI_FUNCTION_DESCRIPTOR_TTL_MS
|
|
3554
|
+
});
|
|
3555
|
+
}
|
|
3556
|
+
async getCachedDescriptor(functionKey) {
|
|
3557
|
+
const hit = this.descriptorCache.get(functionKey);
|
|
3558
|
+
if (hit && hit.expiresAt > Date.now()) return hit.descriptor;
|
|
3559
|
+
return this.get(functionKey);
|
|
3560
|
+
}
|
|
3561
|
+
mapRunError(error, functionKey) {
|
|
3562
|
+
if (!(error instanceof CadraError)) return error;
|
|
3563
|
+
if (error.serverCode === "DUPLICATE_REQUEST") {
|
|
3564
|
+
return new AiFunctionDuplicateError(error.message, error.details, error.requestId);
|
|
3565
|
+
}
|
|
3566
|
+
if (error.details?.charged === true) {
|
|
3567
|
+
return new AiFunctionChargedError(error);
|
|
3568
|
+
}
|
|
3569
|
+
if (functionKey && error.serverCode?.startsWith("VARIABLE_")) {
|
|
3570
|
+
this.descriptorCache.delete(functionKey);
|
|
3571
|
+
}
|
|
3572
|
+
return error;
|
|
3573
|
+
}
|
|
3574
|
+
};
|
|
3575
|
+
|
|
3366
3576
|
// src/client.ts
|
|
3367
3577
|
var DEFAULT_BASE_URL = "https://api.cadraos.com";
|
|
3368
3578
|
var DEFAULT_TIMEOUT = 3e4;
|
|
@@ -3409,6 +3619,10 @@ var CadraClient = class {
|
|
|
3409
3619
|
* Remote runner operations (list)
|
|
3410
3620
|
*/
|
|
3411
3621
|
remoteRunners;
|
|
3622
|
+
/**
|
|
3623
|
+
* AI function operations (list, get, run, getRun) — p93
|
|
3624
|
+
*/
|
|
3625
|
+
aiFunctions;
|
|
3412
3626
|
/**
|
|
3413
3627
|
* Create a new AI SaaS client
|
|
3414
3628
|
*
|
|
@@ -3498,6 +3712,7 @@ var CadraClient = class {
|
|
|
3498
3712
|
this.kanban = new KanbanAPI(this.httpClient, getStreamConfig);
|
|
3499
3713
|
this.remoteAgents = new RemoteAgentsAPI(this.httpClient, getStreamConfig);
|
|
3500
3714
|
this.remoteRunners = new RemoteRunnersAPI(this.httpClient);
|
|
3715
|
+
this.aiFunctions = new AiFunctionsAPI(this.httpClient);
|
|
3501
3716
|
}
|
|
3502
3717
|
/**
|
|
3503
3718
|
* Validate client options
|
|
@@ -4187,6 +4402,32 @@ function useExecutionStream(options) {
|
|
|
4187
4402
|
};
|
|
4188
4403
|
}
|
|
4189
4404
|
|
|
4405
|
+
// src/chat/utils/toolOutcome.ts
|
|
4406
|
+
var MAX_ERROR_CHARS = 500;
|
|
4407
|
+
function asRecord(value) {
|
|
4408
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
4409
|
+
}
|
|
4410
|
+
function errorFrom(value) {
|
|
4411
|
+
if (typeof value === "string" && value.trim()) return value;
|
|
4412
|
+
const rec = asRecord(value);
|
|
4413
|
+
if (rec && typeof rec.message === "string" && rec.message.trim()) return rec.message;
|
|
4414
|
+
return void 0;
|
|
4415
|
+
}
|
|
4416
|
+
function isFailurePayload(result) {
|
|
4417
|
+
const rec = asRecord(result);
|
|
4418
|
+
if (!rec) return false;
|
|
4419
|
+
return rec.success === false || rec.isError === true;
|
|
4420
|
+
}
|
|
4421
|
+
function cap(text) {
|
|
4422
|
+
return text.length > MAX_ERROR_CHARS ? `${text.slice(0, MAX_ERROR_CHARS)}\u2026` : text;
|
|
4423
|
+
}
|
|
4424
|
+
function resolveToolOutcome(input) {
|
|
4425
|
+
const failed = input.isError === true || input.status === "failed" || input.success === false || input.payloadFailure === true || isFailurePayload(input.result);
|
|
4426
|
+
if (!failed) return { status: "completed" };
|
|
4427
|
+
const error = errorFrom(input.error) ?? errorFrom(asRecord(input.result)?.error) ?? "Tool call failed";
|
|
4428
|
+
return { status: "failed", error: cap(error) };
|
|
4429
|
+
}
|
|
4430
|
+
|
|
4190
4431
|
// src/chat/hooks/history-cache.ts
|
|
4191
4432
|
var DEFAULT_HISTORY_STALE_MS = 1e4;
|
|
4192
4433
|
var cache = /* @__PURE__ */ new Map();
|
|
@@ -4362,9 +4603,10 @@ function applyEventInner(state, event) {
|
|
|
4362
4603
|
if (tc) {
|
|
4363
4604
|
toolCalls.set(event.id, {
|
|
4364
4605
|
...tc,
|
|
4365
|
-
status: "completed",
|
|
4606
|
+
status: event.status ?? "completed",
|
|
4366
4607
|
result: event.result,
|
|
4367
|
-
durationMs: event.durationMs
|
|
4608
|
+
durationMs: event.durationMs,
|
|
4609
|
+
...event.error !== void 0 ? { error: event.error } : {}
|
|
4368
4610
|
});
|
|
4369
4611
|
return { ...state, toolCalls };
|
|
4370
4612
|
}
|
|
@@ -4373,8 +4615,9 @@ function applyEventInner(state, event) {
|
|
|
4373
4615
|
name: event.toolName ?? "unknown",
|
|
4374
4616
|
args: {},
|
|
4375
4617
|
result: event.result,
|
|
4376
|
-
status: "completed",
|
|
4377
|
-
durationMs: event.durationMs
|
|
4618
|
+
status: event.status ?? "completed",
|
|
4619
|
+
durationMs: event.durationMs,
|
|
4620
|
+
...event.error !== void 0 ? { error: event.error } : {}
|
|
4378
4621
|
});
|
|
4379
4622
|
if (state.seenToolBlockIds.has(event.id)) {
|
|
4380
4623
|
return { ...state, toolCalls };
|
|
@@ -4624,8 +4867,16 @@ function useAgentChat(options) {
|
|
|
4624
4867
|
const streamMsgId = streamingMessageIdRef.current;
|
|
4625
4868
|
setMessages((prev) => {
|
|
4626
4869
|
const resolvedContent = streamingContentRef.current || finalOutput || "";
|
|
4870
|
+
const streamIdx = prev.findIndex((msg) => msg.id === streamMsgId);
|
|
4871
|
+
let turnStart = 0;
|
|
4872
|
+
for (let i = streamIdx - 1; i >= 0; i--) {
|
|
4873
|
+
if (prev[i].role === "user") {
|
|
4874
|
+
turnStart = i + 1;
|
|
4875
|
+
break;
|
|
4876
|
+
}
|
|
4877
|
+
}
|
|
4627
4878
|
const duplicateExists = resolvedContent && prev.some(
|
|
4628
|
-
(msg) => msg.id !== streamMsgId && msg.role === "assistant" && !msg.isStreaming && msg.content === resolvedContent
|
|
4879
|
+
(msg, idx) => idx >= turnStart && msg.id !== streamMsgId && msg.role === "assistant" && !msg.isStreaming && msg.content === resolvedContent
|
|
4629
4880
|
);
|
|
4630
4881
|
if (duplicateExists) {
|
|
4631
4882
|
return prev.filter((msg) => msg.id !== streamMsgId);
|
|
@@ -4746,6 +4997,17 @@ function useAgentChat(options) {
|
|
|
4746
4997
|
const resultToolCallId = log.metadata?.toolCallId;
|
|
4747
4998
|
const result = log.metadata?.output;
|
|
4748
4999
|
const durationMs = log.durationMs;
|
|
5000
|
+
const outcome = resolveToolOutcome({
|
|
5001
|
+
result,
|
|
5002
|
+
success: log.metadata?.success,
|
|
5003
|
+
payloadFailure: log.metadata?.payloadFailure,
|
|
5004
|
+
isError: log.metadata?.isError,
|
|
5005
|
+
error: log.metadata?.error
|
|
5006
|
+
});
|
|
5007
|
+
const outcomeFields = {
|
|
5008
|
+
status: outcome.status,
|
|
5009
|
+
...outcome.error ? { error: outcome.error } : {}
|
|
5010
|
+
};
|
|
4749
5011
|
let matchedToolCall = resultToolCallId ? pendingToolCallsRef.current.get(resultToolCallId) : void 0;
|
|
4750
5012
|
if (!matchedToolCall) {
|
|
4751
5013
|
for (const [, tc] of pendingToolCallsRef.current) {
|
|
@@ -4759,7 +5021,7 @@ function useAgentChat(options) {
|
|
|
4759
5021
|
const completedToolCall = {
|
|
4760
5022
|
...matchedToolCall,
|
|
4761
5023
|
result,
|
|
4762
|
-
|
|
5024
|
+
...outcomeFields,
|
|
4763
5025
|
durationMs
|
|
4764
5026
|
};
|
|
4765
5027
|
updateToolCall(completedToolCall);
|
|
@@ -4770,7 +5032,7 @@ function useAgentChat(options) {
|
|
|
4770
5032
|
name: resultToolName || "unknown",
|
|
4771
5033
|
args: {},
|
|
4772
5034
|
result,
|
|
4773
|
-
|
|
5035
|
+
...outcomeFields,
|
|
4774
5036
|
durationMs
|
|
4775
5037
|
};
|
|
4776
5038
|
updateToolCall(lateToolCall);
|
|
@@ -4781,7 +5043,8 @@ function useAgentChat(options) {
|
|
|
4781
5043
|
id: resultToolCallId,
|
|
4782
5044
|
toolName: resultToolName,
|
|
4783
5045
|
result,
|
|
4784
|
-
durationMs
|
|
5046
|
+
durationMs,
|
|
5047
|
+
...outcomeFields
|
|
4785
5048
|
});
|
|
4786
5049
|
firedToolResultsRef.current.add(resultToolCallId);
|
|
4787
5050
|
}
|
|
@@ -4891,6 +5154,17 @@ function useAgentChat(options) {
|
|
|
4891
5154
|
const resultToolCallId = log.metadata?.toolCallId;
|
|
4892
5155
|
const result = log.metadata?.output;
|
|
4893
5156
|
const durationMs = log.durationMs;
|
|
5157
|
+
const outcome = resolveToolOutcome({
|
|
5158
|
+
result,
|
|
5159
|
+
success: log.metadata?.success,
|
|
5160
|
+
payloadFailure: log.metadata?.payloadFailure,
|
|
5161
|
+
isError: log.metadata?.isError,
|
|
5162
|
+
error: log.metadata?.error
|
|
5163
|
+
});
|
|
5164
|
+
const outcomeFields = {
|
|
5165
|
+
status: outcome.status,
|
|
5166
|
+
...outcome.error ? { error: outcome.error } : {}
|
|
5167
|
+
};
|
|
4894
5168
|
let matchedToolCall = resultToolCallId ? pendingToolCallsRef.current.get(resultToolCallId) : void 0;
|
|
4895
5169
|
if (!matchedToolCall) {
|
|
4896
5170
|
for (const [, tc] of pendingToolCallsRef.current) {
|
|
@@ -4904,7 +5178,7 @@ function useAgentChat(options) {
|
|
|
4904
5178
|
const completedToolCall = {
|
|
4905
5179
|
...matchedToolCall,
|
|
4906
5180
|
result,
|
|
4907
|
-
|
|
5181
|
+
...outcomeFields,
|
|
4908
5182
|
durationMs
|
|
4909
5183
|
};
|
|
4910
5184
|
updateToolCall(completedToolCall);
|
|
@@ -4915,7 +5189,7 @@ function useAgentChat(options) {
|
|
|
4915
5189
|
name: resultToolName || "unknown",
|
|
4916
5190
|
args: {},
|
|
4917
5191
|
result,
|
|
4918
|
-
|
|
5192
|
+
...outcomeFields,
|
|
4919
5193
|
durationMs
|
|
4920
5194
|
};
|
|
4921
5195
|
updateToolCall(lateToolCall);
|
|
@@ -4926,7 +5200,8 @@ function useAgentChat(options) {
|
|
|
4926
5200
|
id: resultToolCallId,
|
|
4927
5201
|
toolName: resultToolName,
|
|
4928
5202
|
result,
|
|
4929
|
-
durationMs
|
|
5203
|
+
durationMs,
|
|
5204
|
+
...outcomeFields
|
|
4930
5205
|
});
|
|
4931
5206
|
}
|
|
4932
5207
|
if (resultToolCallId) {
|
|
@@ -5175,12 +5450,22 @@ function useAgentChat(options) {
|
|
|
5175
5450
|
if (SILENT_TOOL_NAMES.has(toolName) || isUuidLikeToolName(toolName)) return;
|
|
5176
5451
|
if (firedToolResultsRef.current.has(toolCallId)) return;
|
|
5177
5452
|
const existing = pendingToolCallsRef.current.get(toolCallId);
|
|
5178
|
-
if (existing && existing.status === "completed") return;
|
|
5453
|
+
if (existing && (existing.status === "completed" || existing.status === "failed")) return;
|
|
5454
|
+
const outcome = resolveToolOutcome({
|
|
5455
|
+
result: data.result,
|
|
5456
|
+
isError: data.isError,
|
|
5457
|
+
status: data.status,
|
|
5458
|
+
error: data.error
|
|
5459
|
+
});
|
|
5460
|
+
const outcomeFields = {
|
|
5461
|
+
status: outcome.status,
|
|
5462
|
+
...outcome.error ? { error: outcome.error } : {}
|
|
5463
|
+
};
|
|
5179
5464
|
if (existing) {
|
|
5180
5465
|
const completedToolCall = {
|
|
5181
5466
|
...existing,
|
|
5182
5467
|
result: data.result,
|
|
5183
|
-
|
|
5468
|
+
...outcomeFields,
|
|
5184
5469
|
durationMs: data.durationMs
|
|
5185
5470
|
};
|
|
5186
5471
|
updateToolCall(completedToolCall);
|
|
@@ -5191,7 +5476,7 @@ function useAgentChat(options) {
|
|
|
5191
5476
|
name: toolName,
|
|
5192
5477
|
args: {},
|
|
5193
5478
|
result: data.result,
|
|
5194
|
-
|
|
5479
|
+
...outcomeFields,
|
|
5195
5480
|
durationMs: data.durationMs
|
|
5196
5481
|
};
|
|
5197
5482
|
updateToolCall(lateToolCall);
|
|
@@ -5202,6 +5487,7 @@ function useAgentChat(options) {
|
|
|
5202
5487
|
toolName,
|
|
5203
5488
|
result: data.result,
|
|
5204
5489
|
durationMs: data.durationMs,
|
|
5490
|
+
...outcomeFields,
|
|
5205
5491
|
// CAD-87 S1-003: (execId, seq) reducer dedup for replayed events.
|
|
5206
5492
|
execId: data.sourceExecutionId,
|
|
5207
5493
|
seq: data.seq
|