@cadraos/sdk 0.3.14-p46.3 → 0.3.14
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/board-host/index.cjs +217 -129
- package/dist/board-host/index.cjs.map +1 -1
- package/dist/board-host/index.d.cts +96 -1
- package/dist/board-host/index.d.ts +96 -1
- package/dist/board-host/index.js +218 -131
- package/dist/board-host/index.js.map +1 -1
- package/dist/board-host/server/index.d.cts +44 -0
- package/dist/board-host/server/index.d.ts +44 -0
- package/dist/chat/index.cjs +299 -17
- package/dist/chat/index.cjs.map +1 -1
- package/dist/chat/index.d.cts +225 -0
- package/dist/chat/index.d.ts +225 -0
- package/dist/chat/index.js +299 -17
- package/dist/chat/index.js.map +1 -1
- package/dist/index.cjs +221 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +286 -1
- package/dist/index.d.ts +286 -1
- package/dist/index.js +215 -4
- package/dist/index.js.map +1 -1
- package/dist/kanban/engine/index.cjs +774 -683
- package/dist/kanban/engine/index.cjs.map +1 -1
- package/dist/kanban/engine/index.d.cts +90 -1
- package/dist/kanban/engine/index.d.ts +90 -1
- package/dist/kanban/engine/index.js +774 -684
- package/dist/kanban/engine/index.js.map +1 -1
- package/dist/kanban/index.cjs +214 -3
- package/dist/kanban/index.cjs.map +1 -1
- package/dist/kanban/index.d.cts +252 -0
- package/dist/kanban/index.d.ts +252 -0
- package/dist/kanban/index.js +214 -3
- package/dist/kanban/index.js.map +1 -1
- package/dist/teams/index.cjs +214 -3
- package/dist/teams/index.cjs.map +1 -1
- package/dist/teams/index.d.cts +225 -0
- package/dist/teams/index.d.ts +225 -0
- package/dist/teams/index.js +214 -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,
|
|
@@ -298,7 +348,8 @@ var HttpClient = class {
|
|
|
298
348
|
headers["Idempotency-Key"] = options.idempotencyKey;
|
|
299
349
|
}
|
|
300
350
|
const controller = new AbortController();
|
|
301
|
-
const
|
|
351
|
+
const timeoutMs = options.timeoutMs ?? this.config.timeout;
|
|
352
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
302
353
|
try {
|
|
303
354
|
const doFetch = this.config.fetch ?? fetch;
|
|
304
355
|
const response = await doFetch(url, {
|
|
@@ -334,7 +385,7 @@ var HttpClient = class {
|
|
|
334
385
|
} catch (error) {
|
|
335
386
|
clearTimeout(timeoutId);
|
|
336
387
|
if (error instanceof Error && error.name === "AbortError") {
|
|
337
|
-
throw new TimeoutError(`Request timed out after ${this.config.timeout}ms`);
|
|
388
|
+
throw new TimeoutError(`Request timed out after ${options.timeoutMs ?? this.config.timeout}ms`);
|
|
338
389
|
}
|
|
339
390
|
if (error instanceof TypeError && error.message.includes("fetch")) {
|
|
340
391
|
throw new NetworkError(`Network error: ${error.message}`);
|
|
@@ -366,7 +417,8 @@ var HttpClient = class {
|
|
|
366
417
|
path,
|
|
367
418
|
body,
|
|
368
419
|
idempotencyKey: options?.idempotencyKey,
|
|
369
|
-
skipRetry: options?.skipRetry
|
|
420
|
+
skipRetry: options?.skipRetry,
|
|
421
|
+
timeoutMs: options?.timeoutMs
|
|
370
422
|
});
|
|
371
423
|
}
|
|
372
424
|
/**
|
|
@@ -1125,6 +1177,10 @@ var ExecutionStreamControllerImpl = class {
|
|
|
1125
1177
|
toolName,
|
|
1126
1178
|
result: data.result,
|
|
1127
1179
|
durationMs: data.durationMs ?? 0,
|
|
1180
|
+
// CAD-243: pass the producer's failure verdict through.
|
|
1181
|
+
...data.isError === true ? { isError: true } : {},
|
|
1182
|
+
...typeof data.status === "string" ? { status: data.status } : {},
|
|
1183
|
+
...typeof data.error === "string" ? { error: data.error } : {},
|
|
1128
1184
|
forwardedFrom: event.data._forwardedFrom,
|
|
1129
1185
|
// CAD-87 S1-001 EventIdentity → (execId, seq) reducer dedup (S1-003).
|
|
1130
1186
|
sourceExecutionId: data.sourceExecutionId ?? data.executionId,
|
|
@@ -3363,6 +3419,156 @@ var RemoteRunnersAPI = class extends BaseResourceAPI {
|
|
|
3363
3419
|
}
|
|
3364
3420
|
};
|
|
3365
3421
|
|
|
3422
|
+
// src/resources/ai-functions.ts
|
|
3423
|
+
var AI_FUNCTION_RUN_TIMEOUT_MS = 6e4;
|
|
3424
|
+
var AI_FUNCTION_DESCRIPTOR_TTL_MS = 6e4;
|
|
3425
|
+
function checkAiFunctionParameters(parameters, variables) {
|
|
3426
|
+
const issues = [];
|
|
3427
|
+
const declared = /* @__PURE__ */ new Set();
|
|
3428
|
+
for (const p of parameters) {
|
|
3429
|
+
declared.add(p.name);
|
|
3430
|
+
const has = Object.prototype.hasOwnProperty.call(variables, p.name);
|
|
3431
|
+
const value = has ? variables[p.name] : void 0;
|
|
3432
|
+
if (value === void 0 || value === null) {
|
|
3433
|
+
if (p.required) issues.push({ name: p.name, code: "missing" });
|
|
3434
|
+
continue;
|
|
3435
|
+
}
|
|
3436
|
+
switch (p.type) {
|
|
3437
|
+
case "number":
|
|
3438
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
3439
|
+
issues.push({ name: p.name, code: "type" });
|
|
3440
|
+
}
|
|
3441
|
+
break;
|
|
3442
|
+
case "boolean":
|
|
3443
|
+
if (typeof value !== "boolean") issues.push({ name: p.name, code: "type" });
|
|
3444
|
+
break;
|
|
3445
|
+
case "enum":
|
|
3446
|
+
if (typeof value !== "string") issues.push({ name: p.name, code: "type" });
|
|
3447
|
+
else if (p.options && !p.options.includes(value)) {
|
|
3448
|
+
issues.push({ name: p.name, code: "option" });
|
|
3449
|
+
}
|
|
3450
|
+
break;
|
|
3451
|
+
case "string":
|
|
3452
|
+
case "text":
|
|
3453
|
+
if (typeof value !== "string") issues.push({ name: p.name, code: "type" });
|
|
3454
|
+
else if (typeof p.maxLength === "number" && value.length > p.maxLength) {
|
|
3455
|
+
issues.push({ name: p.name, code: "too_long" });
|
|
3456
|
+
}
|
|
3457
|
+
break;
|
|
3458
|
+
case "image":
|
|
3459
|
+
if (typeof value !== "string") issues.push({ name: p.name, code: "type" });
|
|
3460
|
+
break;
|
|
3461
|
+
}
|
|
3462
|
+
}
|
|
3463
|
+
for (const name of Object.keys(variables)) {
|
|
3464
|
+
if (!declared.has(name)) issues.push({ name, code: "unknown" });
|
|
3465
|
+
}
|
|
3466
|
+
return issues;
|
|
3467
|
+
}
|
|
3468
|
+
var AiFunctionsAPI = class extends BaseResourceAPI {
|
|
3469
|
+
descriptorCache = /* @__PURE__ */ new Map();
|
|
3470
|
+
constructor(http) {
|
|
3471
|
+
super(http, "/api/v1/ai-functions");
|
|
3472
|
+
}
|
|
3473
|
+
/**
|
|
3474
|
+
* List the functions this org can call — the index (D27a). Each entry carries
|
|
3475
|
+
* the live version's typed parameters; never prompt text.
|
|
3476
|
+
*/
|
|
3477
|
+
async list() {
|
|
3478
|
+
const data = await this.httpGet("");
|
|
3479
|
+
const functions = Array.isArray(data) ? data : data?.functions ?? [];
|
|
3480
|
+
for (const d of functions) this.cacheDescriptor(d);
|
|
3481
|
+
return functions;
|
|
3482
|
+
}
|
|
3483
|
+
/**
|
|
3484
|
+
* Get one function's descriptor by key (D27a).
|
|
3485
|
+
* `NotFoundError` (`FUNCTION_NOT_FOUND`) / `ConflictError` (`FUNCTION_NOT_PUBLISHED`).
|
|
3486
|
+
*/
|
|
3487
|
+
async get(functionKey) {
|
|
3488
|
+
const data = await this.httpGet(
|
|
3489
|
+
`/${encodeURIComponent(functionKey)}`
|
|
3490
|
+
);
|
|
3491
|
+
const descriptor = data && typeof data === "object" && "function" in data && !("functionKey" in data) ? data.function : data;
|
|
3492
|
+
this.cacheDescriptor(descriptor, functionKey);
|
|
3493
|
+
return descriptor;
|
|
3494
|
+
}
|
|
3495
|
+
/**
|
|
3496
|
+
* Read one of this org's own runs (safe projection, §6.5).
|
|
3497
|
+
*/
|
|
3498
|
+
async getRun(executionId) {
|
|
3499
|
+
return this.httpGet(`/runs/${encodeURIComponent(executionId)}`);
|
|
3500
|
+
}
|
|
3501
|
+
/** Forget cached descriptors (one key, or all). */
|
|
3502
|
+
clearDescriptorCache(functionKey) {
|
|
3503
|
+
if (functionKey) this.descriptorCache.delete(functionKey);
|
|
3504
|
+
else this.descriptorCache.clear();
|
|
3505
|
+
}
|
|
3506
|
+
async run(refOrKey, parametersOrOptions, shorthandOpts) {
|
|
3507
|
+
let ref;
|
|
3508
|
+
let options;
|
|
3509
|
+
if (typeof refOrKey === "string") {
|
|
3510
|
+
ref = { functionKey: refOrKey };
|
|
3511
|
+
options = { ...shorthandOpts ?? {}, variables: parametersOrOptions };
|
|
3512
|
+
} else {
|
|
3513
|
+
ref = refOrKey;
|
|
3514
|
+
options = parametersOrOptions;
|
|
3515
|
+
}
|
|
3516
|
+
const variables = options.variables ?? {};
|
|
3517
|
+
const functionKey = "functionKey" in ref ? ref.functionKey : void 0;
|
|
3518
|
+
const shouldCheck = functionKey !== void 0 && options.version === void 0 && options.validate !== false;
|
|
3519
|
+
if (shouldCheck) {
|
|
3520
|
+
const descriptor = await this.getCachedDescriptor(functionKey);
|
|
3521
|
+
const issues = checkAiFunctionParameters(descriptor.parameters, variables);
|
|
3522
|
+
if (issues.length > 0) {
|
|
3523
|
+
throw new AiFunctionParameterError(functionKey, issues);
|
|
3524
|
+
}
|
|
3525
|
+
}
|
|
3526
|
+
const body = {
|
|
3527
|
+
ref,
|
|
3528
|
+
variables,
|
|
3529
|
+
version: options.version,
|
|
3530
|
+
idempotencyKey: options.idempotencyKey ?? generateExecutionId(),
|
|
3531
|
+
params: options.params
|
|
3532
|
+
};
|
|
3533
|
+
try {
|
|
3534
|
+
return await this.httpPost("/run", body, {
|
|
3535
|
+
skipRetry: true,
|
|
3536
|
+
timeoutMs: AI_FUNCTION_RUN_TIMEOUT_MS
|
|
3537
|
+
});
|
|
3538
|
+
} catch (error) {
|
|
3539
|
+
throw this.mapRunError(error, functionKey);
|
|
3540
|
+
}
|
|
3541
|
+
}
|
|
3542
|
+
// ── internals ──────────────────────────────────────────────────────────────
|
|
3543
|
+
cacheDescriptor(descriptor, key) {
|
|
3544
|
+
if (!descriptor || typeof descriptor !== "object") return;
|
|
3545
|
+
const cacheKey = key ?? descriptor.functionKey;
|
|
3546
|
+
if (!cacheKey) return;
|
|
3547
|
+
this.descriptorCache.set(cacheKey, {
|
|
3548
|
+
descriptor,
|
|
3549
|
+
expiresAt: Date.now() + AI_FUNCTION_DESCRIPTOR_TTL_MS
|
|
3550
|
+
});
|
|
3551
|
+
}
|
|
3552
|
+
async getCachedDescriptor(functionKey) {
|
|
3553
|
+
const hit = this.descriptorCache.get(functionKey);
|
|
3554
|
+
if (hit && hit.expiresAt > Date.now()) return hit.descriptor;
|
|
3555
|
+
return this.get(functionKey);
|
|
3556
|
+
}
|
|
3557
|
+
mapRunError(error, functionKey) {
|
|
3558
|
+
if (!(error instanceof CadraError)) return error;
|
|
3559
|
+
if (error.serverCode === "DUPLICATE_REQUEST") {
|
|
3560
|
+
return new AiFunctionDuplicateError(error.message, error.details, error.requestId);
|
|
3561
|
+
}
|
|
3562
|
+
if (error.details?.charged === true) {
|
|
3563
|
+
return new AiFunctionChargedError(error);
|
|
3564
|
+
}
|
|
3565
|
+
if (functionKey && error.serverCode?.startsWith("VARIABLE_")) {
|
|
3566
|
+
this.descriptorCache.delete(functionKey);
|
|
3567
|
+
}
|
|
3568
|
+
return error;
|
|
3569
|
+
}
|
|
3570
|
+
};
|
|
3571
|
+
|
|
3366
3572
|
// src/client.ts
|
|
3367
3573
|
var DEFAULT_BASE_URL = "https://api.cadraos.com";
|
|
3368
3574
|
var DEFAULT_TIMEOUT = 3e4;
|
|
@@ -3409,6 +3615,10 @@ var CadraClient = class {
|
|
|
3409
3615
|
* Remote runner operations (list)
|
|
3410
3616
|
*/
|
|
3411
3617
|
remoteRunners;
|
|
3618
|
+
/**
|
|
3619
|
+
* AI function operations (list, get, run, getRun) — p93
|
|
3620
|
+
*/
|
|
3621
|
+
aiFunctions;
|
|
3412
3622
|
/**
|
|
3413
3623
|
* Create a new AI SaaS client
|
|
3414
3624
|
*
|
|
@@ -3498,6 +3708,7 @@ var CadraClient = class {
|
|
|
3498
3708
|
this.kanban = new KanbanAPI(this.httpClient, getStreamConfig);
|
|
3499
3709
|
this.remoteAgents = new RemoteAgentsAPI(this.httpClient, getStreamConfig);
|
|
3500
3710
|
this.remoteRunners = new RemoteRunnersAPI(this.httpClient);
|
|
3711
|
+
this.aiFunctions = new AiFunctionsAPI(this.httpClient);
|
|
3501
3712
|
}
|
|
3502
3713
|
/**
|
|
3503
3714
|
* Validate client options
|
|
@@ -4187,6 +4398,32 @@ function useExecutionStream(options) {
|
|
|
4187
4398
|
};
|
|
4188
4399
|
}
|
|
4189
4400
|
|
|
4401
|
+
// src/chat/utils/toolOutcome.ts
|
|
4402
|
+
var MAX_ERROR_CHARS = 500;
|
|
4403
|
+
function asRecord(value) {
|
|
4404
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
4405
|
+
}
|
|
4406
|
+
function errorFrom(value) {
|
|
4407
|
+
if (typeof value === "string" && value.trim()) return value;
|
|
4408
|
+
const rec = asRecord(value);
|
|
4409
|
+
if (rec && typeof rec.message === "string" && rec.message.trim()) return rec.message;
|
|
4410
|
+
return void 0;
|
|
4411
|
+
}
|
|
4412
|
+
function isFailurePayload(result) {
|
|
4413
|
+
const rec = asRecord(result);
|
|
4414
|
+
if (!rec) return false;
|
|
4415
|
+
return rec.success === false || rec.isError === true;
|
|
4416
|
+
}
|
|
4417
|
+
function cap(text) {
|
|
4418
|
+
return text.length > MAX_ERROR_CHARS ? `${text.slice(0, MAX_ERROR_CHARS)}\u2026` : text;
|
|
4419
|
+
}
|
|
4420
|
+
function resolveToolOutcome(input) {
|
|
4421
|
+
const failed = input.isError === true || input.status === "failed" || input.success === false || input.payloadFailure === true || isFailurePayload(input.result);
|
|
4422
|
+
if (!failed) return { status: "completed" };
|
|
4423
|
+
const error = errorFrom(input.error) ?? errorFrom(asRecord(input.result)?.error) ?? "Tool call failed";
|
|
4424
|
+
return { status: "failed", error: cap(error) };
|
|
4425
|
+
}
|
|
4426
|
+
|
|
4190
4427
|
// src/chat/hooks/history-cache.ts
|
|
4191
4428
|
var DEFAULT_HISTORY_STALE_MS = 1e4;
|
|
4192
4429
|
var cache = /* @__PURE__ */ new Map();
|
|
@@ -4362,9 +4599,10 @@ function applyEventInner(state, event) {
|
|
|
4362
4599
|
if (tc) {
|
|
4363
4600
|
toolCalls.set(event.id, {
|
|
4364
4601
|
...tc,
|
|
4365
|
-
status: "completed",
|
|
4602
|
+
status: event.status ?? "completed",
|
|
4366
4603
|
result: event.result,
|
|
4367
|
-
durationMs: event.durationMs
|
|
4604
|
+
durationMs: event.durationMs,
|
|
4605
|
+
...event.error !== void 0 ? { error: event.error } : {}
|
|
4368
4606
|
});
|
|
4369
4607
|
return { ...state, toolCalls };
|
|
4370
4608
|
}
|
|
@@ -4373,8 +4611,9 @@ function applyEventInner(state, event) {
|
|
|
4373
4611
|
name: event.toolName ?? "unknown",
|
|
4374
4612
|
args: {},
|
|
4375
4613
|
result: event.result,
|
|
4376
|
-
status: "completed",
|
|
4377
|
-
durationMs: event.durationMs
|
|
4614
|
+
status: event.status ?? "completed",
|
|
4615
|
+
durationMs: event.durationMs,
|
|
4616
|
+
...event.error !== void 0 ? { error: event.error } : {}
|
|
4378
4617
|
});
|
|
4379
4618
|
if (state.seenToolBlockIds.has(event.id)) {
|
|
4380
4619
|
return { ...state, toolCalls };
|
|
@@ -4624,8 +4863,16 @@ function useAgentChat(options) {
|
|
|
4624
4863
|
const streamMsgId = streamingMessageIdRef.current;
|
|
4625
4864
|
setMessages((prev) => {
|
|
4626
4865
|
const resolvedContent = streamingContentRef.current || finalOutput || "";
|
|
4866
|
+
const streamIdx = prev.findIndex((msg) => msg.id === streamMsgId);
|
|
4867
|
+
let turnStart = 0;
|
|
4868
|
+
for (let i = streamIdx - 1; i >= 0; i--) {
|
|
4869
|
+
if (prev[i].role === "user") {
|
|
4870
|
+
turnStart = i + 1;
|
|
4871
|
+
break;
|
|
4872
|
+
}
|
|
4873
|
+
}
|
|
4627
4874
|
const duplicateExists = resolvedContent && prev.some(
|
|
4628
|
-
(msg) => msg.id !== streamMsgId && msg.role === "assistant" && !msg.isStreaming && msg.content === resolvedContent
|
|
4875
|
+
(msg, idx) => idx >= turnStart && msg.id !== streamMsgId && msg.role === "assistant" && !msg.isStreaming && msg.content === resolvedContent
|
|
4629
4876
|
);
|
|
4630
4877
|
if (duplicateExists) {
|
|
4631
4878
|
return prev.filter((msg) => msg.id !== streamMsgId);
|
|
@@ -4746,6 +4993,17 @@ function useAgentChat(options) {
|
|
|
4746
4993
|
const resultToolCallId = log.metadata?.toolCallId;
|
|
4747
4994
|
const result = log.metadata?.output;
|
|
4748
4995
|
const durationMs = log.durationMs;
|
|
4996
|
+
const outcome = resolveToolOutcome({
|
|
4997
|
+
result,
|
|
4998
|
+
success: log.metadata?.success,
|
|
4999
|
+
payloadFailure: log.metadata?.payloadFailure,
|
|
5000
|
+
isError: log.metadata?.isError,
|
|
5001
|
+
error: log.metadata?.error
|
|
5002
|
+
});
|
|
5003
|
+
const outcomeFields = {
|
|
5004
|
+
status: outcome.status,
|
|
5005
|
+
...outcome.error ? { error: outcome.error } : {}
|
|
5006
|
+
};
|
|
4749
5007
|
let matchedToolCall = resultToolCallId ? pendingToolCallsRef.current.get(resultToolCallId) : void 0;
|
|
4750
5008
|
if (!matchedToolCall) {
|
|
4751
5009
|
for (const [, tc] of pendingToolCallsRef.current) {
|
|
@@ -4759,7 +5017,7 @@ function useAgentChat(options) {
|
|
|
4759
5017
|
const completedToolCall = {
|
|
4760
5018
|
...matchedToolCall,
|
|
4761
5019
|
result,
|
|
4762
|
-
|
|
5020
|
+
...outcomeFields,
|
|
4763
5021
|
durationMs
|
|
4764
5022
|
};
|
|
4765
5023
|
updateToolCall(completedToolCall);
|
|
@@ -4770,7 +5028,7 @@ function useAgentChat(options) {
|
|
|
4770
5028
|
name: resultToolName || "unknown",
|
|
4771
5029
|
args: {},
|
|
4772
5030
|
result,
|
|
4773
|
-
|
|
5031
|
+
...outcomeFields,
|
|
4774
5032
|
durationMs
|
|
4775
5033
|
};
|
|
4776
5034
|
updateToolCall(lateToolCall);
|
|
@@ -4781,7 +5039,8 @@ function useAgentChat(options) {
|
|
|
4781
5039
|
id: resultToolCallId,
|
|
4782
5040
|
toolName: resultToolName,
|
|
4783
5041
|
result,
|
|
4784
|
-
durationMs
|
|
5042
|
+
durationMs,
|
|
5043
|
+
...outcomeFields
|
|
4785
5044
|
});
|
|
4786
5045
|
firedToolResultsRef.current.add(resultToolCallId);
|
|
4787
5046
|
}
|
|
@@ -4891,6 +5150,17 @@ function useAgentChat(options) {
|
|
|
4891
5150
|
const resultToolCallId = log.metadata?.toolCallId;
|
|
4892
5151
|
const result = log.metadata?.output;
|
|
4893
5152
|
const durationMs = log.durationMs;
|
|
5153
|
+
const outcome = resolveToolOutcome({
|
|
5154
|
+
result,
|
|
5155
|
+
success: log.metadata?.success,
|
|
5156
|
+
payloadFailure: log.metadata?.payloadFailure,
|
|
5157
|
+
isError: log.metadata?.isError,
|
|
5158
|
+
error: log.metadata?.error
|
|
5159
|
+
});
|
|
5160
|
+
const outcomeFields = {
|
|
5161
|
+
status: outcome.status,
|
|
5162
|
+
...outcome.error ? { error: outcome.error } : {}
|
|
5163
|
+
};
|
|
4894
5164
|
let matchedToolCall = resultToolCallId ? pendingToolCallsRef.current.get(resultToolCallId) : void 0;
|
|
4895
5165
|
if (!matchedToolCall) {
|
|
4896
5166
|
for (const [, tc] of pendingToolCallsRef.current) {
|
|
@@ -4904,7 +5174,7 @@ function useAgentChat(options) {
|
|
|
4904
5174
|
const completedToolCall = {
|
|
4905
5175
|
...matchedToolCall,
|
|
4906
5176
|
result,
|
|
4907
|
-
|
|
5177
|
+
...outcomeFields,
|
|
4908
5178
|
durationMs
|
|
4909
5179
|
};
|
|
4910
5180
|
updateToolCall(completedToolCall);
|
|
@@ -4915,7 +5185,7 @@ function useAgentChat(options) {
|
|
|
4915
5185
|
name: resultToolName || "unknown",
|
|
4916
5186
|
args: {},
|
|
4917
5187
|
result,
|
|
4918
|
-
|
|
5188
|
+
...outcomeFields,
|
|
4919
5189
|
durationMs
|
|
4920
5190
|
};
|
|
4921
5191
|
updateToolCall(lateToolCall);
|
|
@@ -4926,7 +5196,8 @@ function useAgentChat(options) {
|
|
|
4926
5196
|
id: resultToolCallId,
|
|
4927
5197
|
toolName: resultToolName,
|
|
4928
5198
|
result,
|
|
4929
|
-
durationMs
|
|
5199
|
+
durationMs,
|
|
5200
|
+
...outcomeFields
|
|
4930
5201
|
});
|
|
4931
5202
|
}
|
|
4932
5203
|
if (resultToolCallId) {
|
|
@@ -5175,12 +5446,22 @@ function useAgentChat(options) {
|
|
|
5175
5446
|
if (SILENT_TOOL_NAMES.has(toolName) || isUuidLikeToolName(toolName)) return;
|
|
5176
5447
|
if (firedToolResultsRef.current.has(toolCallId)) return;
|
|
5177
5448
|
const existing = pendingToolCallsRef.current.get(toolCallId);
|
|
5178
|
-
if (existing && existing.status === "completed") return;
|
|
5449
|
+
if (existing && (existing.status === "completed" || existing.status === "failed")) return;
|
|
5450
|
+
const outcome = resolveToolOutcome({
|
|
5451
|
+
result: data.result,
|
|
5452
|
+
isError: data.isError,
|
|
5453
|
+
status: data.status,
|
|
5454
|
+
error: data.error
|
|
5455
|
+
});
|
|
5456
|
+
const outcomeFields = {
|
|
5457
|
+
status: outcome.status,
|
|
5458
|
+
...outcome.error ? { error: outcome.error } : {}
|
|
5459
|
+
};
|
|
5179
5460
|
if (existing) {
|
|
5180
5461
|
const completedToolCall = {
|
|
5181
5462
|
...existing,
|
|
5182
5463
|
result: data.result,
|
|
5183
|
-
|
|
5464
|
+
...outcomeFields,
|
|
5184
5465
|
durationMs: data.durationMs
|
|
5185
5466
|
};
|
|
5186
5467
|
updateToolCall(completedToolCall);
|
|
@@ -5191,7 +5472,7 @@ function useAgentChat(options) {
|
|
|
5191
5472
|
name: toolName,
|
|
5192
5473
|
args: {},
|
|
5193
5474
|
result: data.result,
|
|
5194
|
-
|
|
5475
|
+
...outcomeFields,
|
|
5195
5476
|
durationMs: data.durationMs
|
|
5196
5477
|
};
|
|
5197
5478
|
updateToolCall(lateToolCall);
|
|
@@ -5202,6 +5483,7 @@ function useAgentChat(options) {
|
|
|
5202
5483
|
toolName,
|
|
5203
5484
|
result: data.result,
|
|
5204
5485
|
durationMs: data.durationMs,
|
|
5486
|
+
...outcomeFields,
|
|
5205
5487
|
// CAD-87 S1-003: (execId, seq) reducer dedup for replayed events.
|
|
5206
5488
|
execId: data.sourceExecutionId,
|
|
5207
5489
|
seq: data.seq
|