@standardagents/builder 0.22.1 → 0.24.0

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.
Files changed (33) hide show
  1. package/dist/built-in-routes.js +196 -58
  2. package/dist/built-in-routes.js.map +1 -1
  3. package/dist/client/{ApiKeysView-N0JkbRqs.js → ApiKeysView-1m7uIS8S.js} +1 -1
  4. package/dist/client/{CenteredContentView-DTm87Sif.js → CenteredContentView-DJzHRMGj.js} +1 -1
  5. package/dist/client/{CompositionView-DnSaz1Nk.js → CompositionView-nzqzVKAg.js} +1 -1
  6. package/dist/client/{ConfirmDialog.vue_vue_type_script_setup_true_lang-DgfpzkTb.js → ConfirmDialog.vue_vue_type_script_setup_true_lang-YX8WE_iB.js} +1 -1
  7. package/dist/client/{CopyButton.vue_vue_type_script_setup_true_lang-DaO8fv5n.js → CopyButton.vue_vue_type_script_setup_true_lang-BpJt6BT0.js} +1 -1
  8. package/dist/client/{DataTable.vue_vue_type_script_setup_true_lang-CXfKtM8R.js → DataTable.vue_vue_type_script_setup_true_lang-Dg3HMMJ0.js} +1 -1
  9. package/dist/client/{JsonViewer-dnp9s6ji.js → JsonViewer-BdNA5OCG.js} +1 -1
  10. package/dist/client/{LoginView-C4vODzeq.js → LoginView-BlF_2TtB.js} +1 -1
  11. package/dist/client/{MarketplaceView-D4QuJAyk.js → MarketplaceView-DrlOb57k.js} +1 -1
  12. package/dist/client/{Modal.vue_vue_type_script_setup_true_lang-DbzeQ2-L.js → Modal.vue_vue_type_script_setup_true_lang-hkOmEwrb.js} +1 -1
  13. package/dist/client/{ModelModal.vue_vue_type_script_setup_true_lang-CNIgneiU.js → ModelModal.vue_vue_type_script_setup_true_lang-p3esoV-i.js} +1 -1
  14. package/dist/client/{ModelsView-CYQm6yLC.js → ModelsView-CHBanMSH.js} +1 -1
  15. package/dist/client/{PromptEditView-BAJoqY8N.js → PromptEditView-b5B43l4Q.js} +1 -1
  16. package/dist/client/{PromptModal-CFd4gHai.js → PromptModal-BF5bdmNQ.js} +1 -1
  17. package/dist/client/{PromptsView-DDapP7U-.js → PromptsView-6TfMOScI.js} +1 -1
  18. package/dist/client/{ProvidersView-D2g5wSI1.js → ProvidersView-CA5Yx2Fn.js} +1 -1
  19. package/dist/client/{ThreadInspectorPane.vue_vue_type_script_setup_true_lang-Cyvuox_G.js → ThreadInspectorPane.vue_vue_type_script_setup_true_lang-ejyFhmNy.js} +15 -15
  20. package/dist/client/{ThreadsView-Dc3lr6Au.js → ThreadsView-yJpVmf42.js} +1 -1
  21. package/dist/client/{ToolsView-C-marn6m.js → ToolsView-DE1TDnlU.js} +1 -1
  22. package/dist/client/{UsersView-D4j8izbK.js → UsersView-BXDHjJLB.js} +1 -1
  23. package/dist/client/{VariablesView-d3lOE_O2.js → VariablesView-Bz-CbaEv.js} +1 -1
  24. package/dist/client/assets/index-V68N0r_5.css +1 -0
  25. package/dist/client/{index-DR9DbKrm.js → index-TIntu1KJ.js} +2 -2
  26. package/dist/client/index.html +2 -2
  27. package/dist/index.js +66 -3
  28. package/dist/index.js.map +1 -1
  29. package/dist/runtime.d.ts +29 -0
  30. package/dist/runtime.js +66 -3
  31. package/dist/runtime.js.map +1 -1
  32. package/package.json +5 -5
  33. package/dist/client/assets/index-_JaOWezk.css +0 -1
@@ -5755,7 +5755,7 @@ ${attachmentPaths}`;
5755
5755
  const attachmentId = crypto.randomUUID();
5756
5756
  const timestamp = Date.now();
5757
5757
  const ext = attachment.mimeType === "image/png" ? "png" : attachment.mimeType === "image/jpeg" ? "jpg" : attachment.mimeType === "image/gif" ? "gif" : attachment.mimeType === "image/webp" ? "webp" : attachment.name.split(".").pop() || "bin";
5758
- const path9 = `/attachments/${timestamp}-${attachmentId}.${ext}`;
5758
+ const path9 = `/attachments/${timestamp}-${attachmentId.slice(0, 8)}.${ext}`;
5759
5759
  const binaryString = atob(attachment.data);
5760
5760
  const dataBuffer = new Uint8Array(binaryString.length);
5761
5761
  for (let i = 0; i < binaryString.length; i++) {
@@ -9342,7 +9342,7 @@ ${lines.join("\n\n")}`
9342
9342
  const base64Data = match2[2];
9343
9343
  const ext = mimeType.split("/")[1] || "png";
9344
9344
  const attachmentId = crypto.randomUUID();
9345
- const path9 = `/attachments/${Date.now()}-${attachmentId}.${ext}`;
9345
+ const path9 = `/attachments/${Date.now()}-${attachmentId.slice(0, 8)}.${ext}`;
9346
9346
  try {
9347
9347
  await state.thread.instance.writeFile(path9, base64Data, mimeType);
9348
9348
  if (image.id) {
@@ -9412,7 +9412,7 @@ ${lines.join("\n\n")}`
9412
9412
  const base64Data = imageUrl.slice(base64Index + base64Marker.length);
9413
9413
  const ext = mimeType.split("/")[1] || "png";
9414
9414
  const attachmentId = crypto.randomUUID();
9415
- const path9 = `/attachments/${Date.now()}-${attachmentId}.${ext}`;
9415
+ const path9 = `/attachments/${Date.now()}-${attachmentId.slice(0, 8)}.${ext}`;
9416
9416
  try {
9417
9417
  await state.thread.instance.writeFile(path9, base64Data, mimeType);
9418
9418
  const attachmentRef = {
@@ -64307,14 +64307,13 @@ async function getPlatformIdentity(env2) {
64307
64307
  platformEndpoint: endpoint
64308
64308
  };
64309
64309
  }
64310
- async function mintLocalSessionForPlatformUser(env2, platformUser) {
64310
+ async function upsertReplicaUserForPlatformProfile(env2, profile) {
64311
64311
  const namespace = env2.AGENT_BUILDER;
64312
64312
  if (!namespace || typeof namespace.idFromName !== "function" || typeof namespace.get !== "function") {
64313
64313
  throw new Error("Server misconfigured: AGENT_BUILDER Durable Object binding is required for platform auth");
64314
64314
  }
64315
64315
  const agentBuilder = namespace.get(namespace.idFromName("singleton"));
64316
- const profile = typeof platformUser === "string" ? { platform_user_id: platformUser, username: `sa-${platformUser.slice(0, 12)}`, role: "admin" } : platformUser;
64317
- const user = await agentBuilder.upsertPlatformReplicaUser({
64316
+ return await agentBuilder.upsertPlatformReplicaUser({
64318
64317
  platform_user_id: profile.platform_user_id,
64319
64318
  username: profile.username ?? null,
64320
64319
  display_name: profile.display_name ?? null,
@@ -64323,6 +64322,15 @@ async function mintLocalSessionForPlatformUser(env2, platformUser) {
64323
64322
  role: profile.role ?? "admin",
64324
64323
  permissions: profile.permissions ?? null
64325
64324
  });
64325
+ }
64326
+ async function mintLocalSessionForPlatformUser(env2, platformUser) {
64327
+ const namespace = env2.AGENT_BUILDER;
64328
+ if (!namespace || typeof namespace.idFromName !== "function" || typeof namespace.get !== "function") {
64329
+ throw new Error("Server misconfigured: AGENT_BUILDER Durable Object binding is required for platform auth");
64330
+ }
64331
+ const agentBuilder = namespace.get(namespace.idFromName("singleton"));
64332
+ const profile = typeof platformUser === "string" ? { platform_user_id: platformUser, username: `sa-${platformUser.slice(0, 12)}`, role: "admin" } : platformUser;
64333
+ const user = await upsertReplicaUserForPlatformProfile(env2, profile);
64326
64334
  if (user.role === "api") {
64327
64335
  throw new Error("This account has API-only access. Use an API key instead of signing in.");
64328
64336
  }
@@ -69077,7 +69085,54 @@ var continue_post_default = defineController2(async ({ req, params, env: env2 })
69077
69085
  }
69078
69086
  });
69079
69087
 
69088
+ // src/agents/cost-summary.ts
69089
+ function emptyCostSummary() {
69090
+ return { totalCost: 0, requestCount: 0, messageCount: 0, byModel: {} };
69091
+ }
69092
+ function mergeByModel(summaries) {
69093
+ const merged = {};
69094
+ for (const summary of summaries) {
69095
+ for (const [modelName, acc] of Object.entries(summary.byModel)) {
69096
+ const entry = merged[modelName] ?? { totalCost: 0, count: 0 };
69097
+ entry.totalCost += acc.totalCost;
69098
+ entry.count += acc.count;
69099
+ merged[modelName] = entry;
69100
+ }
69101
+ }
69102
+ return merged;
69103
+ }
69104
+ function sumSummaries(summaries) {
69105
+ let totalCost = 0;
69106
+ let requestCount = 0;
69107
+ let messageCount = 0;
69108
+ for (const summary of summaries) {
69109
+ totalCost += summary.totalCost;
69110
+ requestCount += summary.requestCount;
69111
+ messageCount += summary.messageCount;
69112
+ }
69113
+ return { totalCost, requestCount, messageCount };
69114
+ }
69115
+ function buildModelBreakdown(byModel) {
69116
+ return Object.entries(byModel).map(([modelName, acc]) => ({
69117
+ modelName,
69118
+ totalCost: acc.totalCost,
69119
+ requestCount: acc.count,
69120
+ avgCostPerRequest: acc.count > 0 ? acc.totalCost / acc.count : 0
69121
+ })).sort((a, b) => b.totalCost - a.totalCost);
69122
+ }
69123
+ function threadNameFromTags(tags) {
69124
+ for (const tag of tags ?? []) {
69125
+ if (typeof tag === "string" && tag.startsWith("name:")) {
69126
+ const value = tag.slice("name:".length).trim();
69127
+ if (value) return value;
69128
+ }
69129
+ }
69130
+ return null;
69131
+ }
69132
+
69080
69133
  // src/api/threads/[id]/cost.get.ts
69134
+ var MAX_DESCENDANTS = 200;
69135
+ var SUMMARY_BATCH = 10;
69081
69136
  var cost_get_default = defineController2(async ({ req, params, env: env2 }) => {
69082
69137
  const threadId = params.id;
69083
69138
  if (!threadId) {
@@ -69093,52 +69148,70 @@ var cost_get_default = defineController2(async ({ req, params, env: env2 }) => {
69093
69148
  { status: 404 }
69094
69149
  );
69095
69150
  }
69096
- const durableId = env2.AGENT_BUILDER_THREAD.idFromName(threadId);
69097
- const stub = env2.AGENT_BUILDER_THREAD.get(durableId);
69098
- const logsResult = await stub.getLogs(1e4, 0, "ASC");
69099
- const logs = logsResult.logs || [];
69100
- let totalCost = 0;
69101
- const modelCosts = {};
69102
- const uniqueMessages = /* @__PURE__ */ new Set();
69103
- for (const log of logs) {
69104
- const cost = log.cost_total;
69105
- if (cost !== null && cost !== void 0 && !isNaN(cost)) {
69106
- totalCost += cost;
69107
- if (log.message_id) {
69108
- uniqueMessages.add(log.message_id);
69109
- }
69110
- const modelKey = log.model_name || log.model || "unknown";
69111
- if (!modelCosts[modelKey]) {
69112
- modelCosts[modelKey] = {
69113
- totalCost: 0,
69114
- count: 0
69115
- };
69116
- }
69117
- modelCosts[modelKey].totalCost += cost;
69118
- modelCosts[modelKey].count += 1;
69151
+ const descendants = (await agentBuilder.getDescendantThreads(threadId) ?? []).slice(
69152
+ 0,
69153
+ MAX_DESCENDANTS + 1
69154
+ );
69155
+ const truncated = descendants.length > MAX_DESCENDANTS;
69156
+ if (truncated) descendants.length = MAX_DESCENDANTS;
69157
+ const summarize = async (id) => {
69158
+ try {
69159
+ const durableId = env2.AGENT_BUILDER_THREAD.idFromName(id);
69160
+ const stub = env2.AGENT_BUILDER_THREAD.get(durableId);
69161
+ return await stub.getCostSummary() ?? emptyCostSummary();
69162
+ } catch {
69163
+ return emptyCostSummary();
69119
69164
  }
69165
+ };
69166
+ const ownSummary = await summarize(threadId);
69167
+ const descendantSummaries = [];
69168
+ for (let i = 0; i < descendants.length; i += SUMMARY_BATCH) {
69169
+ const batch = descendants.slice(i, i + SUMMARY_BATCH);
69170
+ descendantSummaries.push(
69171
+ ...await Promise.all(batch.map((child) => summarize(child.id)))
69172
+ );
69120
69173
  }
69121
- const messageCount = uniqueMessages.size;
69122
- const avgCostPerMessage = messageCount > 0 ? totalCost / messageCount : 0;
69174
+ const allSummaries = [ownSummary, ...descendantSummaries];
69175
+ const totals = sumSummaries(allSummaries);
69176
+ const byModel = mergeByModel(allSummaries);
69177
+ const modelBreakdown = buildModelBreakdown(byModel);
69123
69178
  const avgCostPerMessageByModel = {};
69124
- for (const [modelName, data] of Object.entries(modelCosts)) {
69125
- avgCostPerMessageByModel[modelName] = {
69126
- avgCost: data.count > 0 ? data.totalCost / data.count : 0,
69127
- messageCount: data.count
69179
+ for (const entry of modelBreakdown) {
69180
+ avgCostPerMessageByModel[entry.modelName] = {
69181
+ avgCost: entry.avgCostPerRequest,
69182
+ messageCount: entry.requestCount
69128
69183
  };
69129
69184
  }
69130
- const modelBreakdown = Object.entries(modelCosts).map(([modelName, data]) => ({
69131
- modelName,
69132
- totalCost: data.totalCost,
69133
- requestCount: data.count,
69134
- avgCostPerRequest: data.count > 0 ? data.totalCost / data.count : 0
69135
- }));
69185
+ const threads = [
69186
+ {
69187
+ threadId,
69188
+ agentName: thread.agent_name ?? null,
69189
+ threadName: threadNameFromTags(thread.tags),
69190
+ parent: null,
69191
+ isRoot: true,
69192
+ totalCost: ownSummary.totalCost,
69193
+ requestCount: ownSummary.requestCount
69194
+ },
69195
+ ...descendants.map((child, index) => ({
69196
+ threadId: child.id,
69197
+ agentName: child.agent_name ?? null,
69198
+ threadName: threadNameFromTags(child.tags),
69199
+ parent: child.parent,
69200
+ isRoot: false,
69201
+ totalCost: descendantSummaries[index]?.totalCost ?? 0,
69202
+ requestCount: descendantSummaries[index]?.requestCount ?? 0
69203
+ })).filter((row) => row.requestCount > 0)
69204
+ ];
69136
69205
  return Response.json({
69137
- totalCost,
69138
- messageCount,
69139
- avgCostPerMessage,
69206
+ totalCost: totals.totalCost,
69207
+ ownCost: ownSummary.totalCost,
69208
+ requestCount: totals.requestCount,
69209
+ messageCount: totals.messageCount,
69210
+ avgCostPerMessage: totals.messageCount > 0 ? totals.totalCost / totals.messageCount : 0,
69140
69211
  modelBreakdown,
69141
- avgCostPerMessageByModel
69212
+ avgCostPerMessageByModel,
69213
+ threads,
69214
+ truncated
69142
69215
  });
69143
69216
  } catch (error) {
69144
69217
  console.error(`Error calculating cost for thread ${threadId}:`, error);
@@ -69604,7 +69677,7 @@ var messages_post_default = defineController2(async ({ req, params, env: env2 })
69604
69677
  }
69605
69678
  }
69606
69679
  const ext = mimeType === "image/png" ? "png" : mimeType === "image/jpeg" ? "jpg" : attachment.name.split(".").pop() || "bin";
69607
- const path9 = `/attachments/${timestamp}-${attachmentId}.${ext}`;
69680
+ const path9 = `/attachments/${timestamp}-${attachmentId.slice(0, 8)}.${ext}`;
69608
69681
  const base64Size = fileData.length;
69609
69682
  const binarySize = Math.ceil(base64Size * 3 / 4);
69610
69683
  console.log(`[writeFile] Storing ${attachment.name}: ${(binarySize / 1024 / 1024).toFixed(2)}MB binary (${(base64Size / 1024 / 1024).toFixed(2)}MB base64) to ${path9}`);
@@ -70046,9 +70119,11 @@ var start_post_default = defineController2(async ({ req, env: env2 }) => {
70046
70119
  const agentBuilder = env2.AGENT_BUILDER.get(agentBuilderId);
70047
70120
  await agentBuilder.startDeviceLogin(await hashToken(code));
70048
70121
  const origin = new URL(req.url).origin;
70122
+ const verifyBaseRaw = env2.STANDARD_AGENTS_DEVICE_VERIFY_URL_BASE;
70123
+ const verifyBase = typeof verifyBaseRaw === "string" ? verifyBaseRaw.trim().replace(/\/+$/, "") : "";
70049
70124
  return Response.json({
70050
70125
  code,
70051
- verify_url: `${origin}/api/auth/device/${code}/approve`,
70126
+ verify_url: verifyBase ? `${verifyBase}/${code}` : `${origin}/api/auth/device/${code}/approve`,
70052
70127
  poll_url: `${origin}/api/auth/device/${code}`,
70053
70128
  interval: 2,
70054
70129
  expires_in: 600
@@ -70104,6 +70179,15 @@ var callback_get_default = defineController2(async ({ req, env: env2 }) => {
70104
70179
  return failRedirect(req, env2, "forbidden");
70105
70180
  }
70106
70181
  if (payload.role === "api") {
70182
+ const apiReturnTo = safeReturnTo2(url.searchParams.get("return_to"));
70183
+ if (/^\/api\/auth\/device\/[A-Za-z0-9]{8,64}\/approve$/.test(apiReturnTo)) {
70184
+ return new Response(null, {
70185
+ status: 302,
70186
+ headers: {
70187
+ Location: `${url.origin}${apiReturnTo}?handoff=${encodeURIComponent(handoff)}`
70188
+ }
70189
+ });
70190
+ }
70107
70191
  return failRedirect(req, env2, "api_only_account");
70108
70192
  }
70109
70193
  const session = await mintLocalSessionForPlatformUser(env2, {
@@ -70217,23 +70301,49 @@ function page(title, body, ok) {
70217
70301
  var approve_get_default = defineController2(async ({ req, env: env2, params }) => {
70218
70302
  const code = params.code;
70219
70303
  if (!code) return page("Missing code", "This device link is malformed.", false);
70220
- const authResult = await requireAuth(req, env2);
70221
- if (authResult instanceof Response) {
70222
- const url = new URL(req.url);
70223
- const returnTo = encodeURIComponent(url.pathname);
70224
- const hosted = Boolean(env2.STANDARD_AGENTS_HOSTED && String(env2.STANDARD_AGENTS_HOSTED) !== "0" && String(env2.STANDARD_AGENTS_HOSTED).toLowerCase() !== "false");
70225
- const target = hosted ? `/api/auth/sa/start?return_to=${returnTo}` : `/login?return_to=${returnTo}`;
70226
- return new Response(null, { status: 302, headers: { Location: `${url.origin}${target}` } });
70227
- }
70228
- if (authResult.authType === "api_key") {
70229
- return page("Sign in required", "Device logins must be approved from a signed-in browser session.", false);
70304
+ const url = new URL(req.url);
70305
+ let approvingUserId = null;
70306
+ const handoff = url.searchParams.get("handoff");
70307
+ if (handoff && isPlatformHosted(env2)) {
70308
+ const configuredProjectId = typeof env2.STANDARD_AGENTS_PROJECT_ID === "string" ? env2.STANDARD_AGENTS_PROJECT_ID : void 0;
70309
+ const payload = await verifyPlatformSignedPayload(
70310
+ handoff,
70311
+ env2.STANDARD_AGENTS_AUTH_PUBLIC_KEY_JWK ?? env2.STANDARD_AGENTS_AUTH_PUBLIC_KEY,
70312
+ { kind: "instance_handoff", projectId: configuredProjectId }
70313
+ );
70314
+ const projectOk = payload && (configuredProjectId || payload.project_id === hostedInstanceRedirectId(req, env2));
70315
+ if (!payload || !payload.platform_user_id || !payload.role || !projectOk) {
70316
+ return page("Sign in failed", "This sign-in link is invalid or has expired. Start again from your terminal.", false);
70317
+ }
70318
+ const user = await upsertReplicaUserForPlatformProfile(env2, {
70319
+ platform_user_id: payload.platform_user_id,
70320
+ username: payload.username ?? null,
70321
+ display_name: payload.display_name ?? null,
70322
+ email: payload.email ?? null,
70323
+ avatar_url: payload.avatar_url ?? null,
70324
+ role: payload.role,
70325
+ permissions: payload.permissions ?? null
70326
+ });
70327
+ approvingUserId = user.id;
70328
+ } else {
70329
+ const authResult = await requireAuth(req, env2);
70330
+ if (authResult instanceof Response) {
70331
+ const returnTo = encodeURIComponent(url.pathname);
70332
+ const hosted = Boolean(env2.STANDARD_AGENTS_HOSTED && String(env2.STANDARD_AGENTS_HOSTED) !== "0" && String(env2.STANDARD_AGENTS_HOSTED).toLowerCase() !== "false");
70333
+ const target = hosted ? `/api/auth/sa/start?return_to=${returnTo}` : `/login?return_to=${returnTo}`;
70334
+ return new Response(null, { status: 302, headers: { Location: `${url.origin}${target}` } });
70335
+ }
70336
+ if (authResult.authType === "api_key") {
70337
+ return page("Sign in required", "Device logins must be approved from a signed-in browser session.", false);
70338
+ }
70339
+ approvingUserId = authResult.user.id;
70230
70340
  }
70231
70341
  const token = generateApiKey();
70232
70342
  const agentBuilderId = env2.AGENT_BUILDER.idFromName("singleton");
70233
70343
  const agentBuilder = env2.AGENT_BUILDER.get(agentBuilderId);
70234
70344
  const ok = await agentBuilder.approveDeviceLogin({
70235
70345
  code_hash: await hashToken(code),
70236
- user_id: authResult.user.id,
70346
+ user_id: approvingUserId,
70237
70347
  token,
70238
70348
  token_hash: await hashToken(token),
70239
70349
  key_prefix: token.slice(0, 12),
@@ -70639,6 +70749,20 @@ async function handleChunkedUploadComplete(stub, filePath, req) {
70639
70749
 
70640
70750
  // src/api/threads/[id]/logs/[logId].get.ts
70641
70751
  var logId_get_default = defineController2(async ({ req, params, env: env2 }) => {
70752
+ if (isPlatformHosted(env2)) {
70753
+ const authResult = await requirePermission(req, env2, "logs");
70754
+ if (authResult instanceof Response) {
70755
+ return authResult;
70756
+ }
70757
+ } else {
70758
+ const authContext = await authenticate(req, env2);
70759
+ if (authContext && !hasPermission(authContext.user, "logs")) {
70760
+ return Response.json(
70761
+ { error: "Forbidden: 'logs' access required" },
70762
+ { status: 403 }
70763
+ );
70764
+ }
70765
+ }
70642
70766
  const threadId = params.id;
70643
70767
  const logId = params.logId;
70644
70768
  if (!threadId) {
@@ -71054,6 +71178,20 @@ function createInspectProviderConfig(providerName, factory, env2) {
71054
71178
  };
71055
71179
  }
71056
71180
  var provider_get_default = defineController2(async ({ req, params, env: env2 }) => {
71181
+ if (isPlatformHosted(env2)) {
71182
+ const authResult = await requirePermission(req, env2, "logs");
71183
+ if (authResult instanceof Response) {
71184
+ return authResult;
71185
+ }
71186
+ } else {
71187
+ const authContext = await authenticate(req, env2);
71188
+ if (authContext && !hasPermission(authContext.user, "logs")) {
71189
+ return Response.json(
71190
+ { error: "Forbidden: 'logs' access required" },
71191
+ { status: 403 }
71192
+ );
71193
+ }
71194
+ }
71057
71195
  const threadId = params.id;
71058
71196
  const logId = params.logId;
71059
71197
  const providerName = params.provider;