@vellumai/assistant 0.8.9-staging.2 → 0.8.9-staging.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/docs/activation-funnel-telemetry.md +310 -0
  2. package/package.json +1 -1
  3. package/src/__tests__/activation-early-marking.test.ts +120 -0
  4. package/src/__tests__/agent-loop-output-hooks.test.ts +13 -13
  5. package/src/__tests__/approval-cascade.test.ts +1 -1
  6. package/src/__tests__/compaction-direct.test.ts +32 -18
  7. package/src/__tests__/compaction-events.test.ts +2 -2
  8. package/src/__tests__/compaction.benchmark.test.ts +1 -1
  9. package/src/__tests__/context-overflow-reducer.test.ts +5 -5
  10. package/src/__tests__/context-window-manager-compact-retry.test.ts +1 -1
  11. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
  12. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
  13. package/src/__tests__/conversation-error.test.ts +15 -1
  14. package/src/__tests__/conversation-history-web-search.test.ts +5 -0
  15. package/src/__tests__/conversation-media-retry.test.ts +1 -1
  16. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +40 -0
  17. package/src/__tests__/conversation-process-callsite.test.ts +1 -1
  18. package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -1
  19. package/src/__tests__/conversation-queue.test.ts +1 -1
  20. package/src/__tests__/conversation-runtime-assembly.test.ts +71 -0
  21. package/src/__tests__/conversation-slash-queue.test.ts +1 -1
  22. package/src/__tests__/conversation-slash-unknown.test.ts +1 -1
  23. package/src/__tests__/conversation-speed-override.test.ts +1 -1
  24. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +395 -0
  25. package/src/__tests__/conversation-surfaces-app-control.test.ts +44 -0
  26. package/src/__tests__/conversation-undo.test.ts +2 -2
  27. package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -1
  28. package/src/__tests__/conversation-workspace-injection.test.ts +1 -1
  29. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -1
  30. package/src/__tests__/cu-unified-flow.test.ts +36 -0
  31. package/src/__tests__/history-repair-hook.test.ts +2 -0
  32. package/src/__tests__/memory-retrieval-hook.test.ts +1 -2
  33. package/src/__tests__/persist-unsendable-image-downscale.test.ts +145 -0
  34. package/src/__tests__/persist-unsendable-image.test.ts +97 -1
  35. package/src/__tests__/post-turn-tool-result-truncation.test.ts +69 -0
  36. package/src/__tests__/skill-feature-flags-integration.test.ts +5 -7
  37. package/src/__tests__/title-generate-hook.test.ts +2 -0
  38. package/src/__tests__/web-fetch.test.ts +45 -0
  39. package/src/acp/__tests__/helpers/acp-config-stub.ts +0 -2
  40. package/src/acp/resolve-agent.test.ts +0 -56
  41. package/src/acp/resolve-agent.ts +10 -38
  42. package/src/agent/loop.ts +13 -27
  43. package/src/cli/lib/__tests__/install-from-github.test.ts +232 -29
  44. package/src/cli/lib/__tests__/plugin-details.test.ts +28 -19
  45. package/src/cli/lib/__tests__/plugin-marketplace.test.ts +57 -7
  46. package/src/cli/lib/__tests__/search-plugins.test.ts +17 -10
  47. package/src/cli/lib/install-from-github.ts +258 -41
  48. package/src/cli/lib/plugin-details.ts +20 -13
  49. package/src/cli/lib/plugin-marketplace.ts +23 -5
  50. package/src/cli/lib/search-plugins.ts +14 -8
  51. package/src/config/acp-defaults.ts +3 -3
  52. package/src/config/acp-schema.ts +1 -7
  53. package/src/config/bundled-skills/acp/SKILL.md +4 -17
  54. package/src/config/bundled-skills/acp/TOOLS.json +2 -2
  55. package/src/config/feature-flag-registry.json +3 -18
  56. package/src/context/post-turn-tool-result-truncation.ts +39 -1
  57. package/src/daemon/conversation-agent-loop-handlers.ts +8 -1
  58. package/src/daemon/conversation-agent-loop.ts +78 -78
  59. package/src/daemon/conversation-error.ts +31 -4
  60. package/src/daemon/conversation-history.ts +1 -1
  61. package/src/daemon/conversation-media-retry.ts +19 -6
  62. package/src/daemon/conversation-messaging.ts +17 -0
  63. package/src/daemon/conversation-process.ts +14 -5
  64. package/src/daemon/conversation-queue-manager.ts +8 -0
  65. package/src/daemon/conversation-runtime-assembly.ts +37 -1
  66. package/src/daemon/conversation-surfaces.ts +141 -3
  67. package/src/daemon/conversation.ts +48 -13
  68. package/src/daemon/persist-unsendable-image.ts +62 -25
  69. package/src/daemon/process-message.ts +1 -1
  70. package/src/memory/__tests__/activation-session-store.test.ts +41 -0
  71. package/src/memory/__tests__/onboarding-events-store.test.ts +80 -0
  72. package/src/memory/activation-session-store.ts +43 -0
  73. package/src/memory/db-init.ts +4 -0
  74. package/src/memory/migrations/273-onboarding-events-funnel-columns.ts +46 -0
  75. package/src/memory/migrations/274-create-activation-sessions.ts +15 -0
  76. package/src/memory/migrations/index.ts +2 -0
  77. package/src/memory/onboarding-events-store.ts +66 -18
  78. package/src/memory/schema/infrastructure.ts +13 -0
  79. package/src/messaging/providers/telegram-bot/api.ts +14 -5
  80. package/src/notifications/adapters/telegram.ts +7 -1
  81. package/src/plugin-api/constants.ts +2 -2
  82. package/src/plugin-api/index.ts +2 -2
  83. package/src/plugin-api/types.ts +19 -5
  84. package/src/plugins/defaults/compaction/compact.ts +24 -15
  85. package/src/plugins/defaults/compaction/context-overflow-reducer.ts +4 -4
  86. package/src/plugins/defaults/compaction/manager-store.ts +1 -1
  87. package/src/{context → plugins/defaults/compaction}/window-manager.ts +12 -12
  88. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +12 -18
  89. package/src/prompts/system-prompt.ts +61 -10
  90. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +37 -2
  91. package/src/providers/openai/__tests__/vision-not-supported.test.ts +75 -0
  92. package/src/providers/openai/chat-completions-provider.ts +25 -0
  93. package/src/runtime/routes/__tests__/stt-routes.test.ts +112 -0
  94. package/src/runtime/routes/acp-routes.test.ts +3 -20
  95. package/src/runtime/routes/conversation-routes.ts +2 -0
  96. package/src/runtime/routes/playground/__tests__/force-compact.test.ts +1 -1
  97. package/src/runtime/routes/stt-routes.ts +45 -12
  98. package/src/runtime/routes/workspace-routes.ts +50 -15
  99. package/src/telemetry/__tests__/activation-funnel.test.ts +95 -0
  100. package/src/telemetry/activation-funnel.ts +167 -0
  101. package/src/telemetry/types.ts +13 -0
  102. package/src/telemetry/usage-telemetry-reporter.test.ts +154 -0
  103. package/src/telemetry/usage-telemetry-reporter.ts +26 -1
  104. package/src/tools/acp/list-agents.test.ts +2 -18
  105. package/src/tools/acp/list-agents.ts +3 -15
  106. package/src/tools/acp/spawn.test.ts +0 -10
  107. package/src/tools/browser/browser-execution.ts +12 -2
  108. package/src/tools/network/web-fetch.ts +65 -24
  109. package/src/tools/ui-surface/definitions.ts +7 -0
  110. package/src/acp/feature-gate.test.ts +0 -48
  111. package/src/acp/feature-gate.ts +0 -34
@@ -12,7 +12,7 @@ import { describe, expect, mock, test } from "bun:test";
12
12
 
13
13
  import { DEFAULT_CONFIG } from "../config/defaults.js";
14
14
  import { estimatePromptTokens } from "../context/token-estimator.js";
15
- import { ContextWindowManager } from "../context/window-manager.js";
15
+ import { ContextWindowManager } from "../plugins/defaults/compaction/window-manager.js";
16
16
  import type { Message, Provider } from "../providers/types.js";
17
17
 
18
18
  mock.module("../util/logger.js", () => ({
@@ -1,17 +1,17 @@
1
1
  import { describe, expect, test } from "bun:test";
2
2
 
3
3
  import { estimatePromptTokens } from "../context/token-estimator.js";
4
- import type {
5
- ContextWindowCompactOptions,
6
- ContextWindowResult,
7
- } from "../context/window-manager.js";
8
- import { createContextSummaryMessage } from "../context/window-manager.js";
9
4
  import {
10
5
  createInitialReducerState,
11
6
  reduceContextOverflow,
12
7
  type ReducerConfig,
13
8
  type ReducerState,
14
9
  } from "../plugins/defaults/compaction/context-overflow-reducer.js";
10
+ import type {
11
+ ContextWindowCompactOptions,
12
+ ContextWindowResult,
13
+ } from "../plugins/defaults/compaction/window-manager.js";
14
+ import { createContextSummaryMessage } from "../plugins/defaults/compaction/window-manager.js";
15
15
  import type { Message } from "../providers/types.js";
16
16
 
17
17
  function msg(role: "user" | "assistant", text: string): Message {
@@ -94,7 +94,7 @@ mock.module("../context/compactor.js", () => ({
94
94
  },
95
95
  }));
96
96
 
97
- import { ContextWindowManager } from "../context/window-manager.js";
97
+ import { ContextWindowManager } from "../plugins/defaults/compaction/window-manager.js";
98
98
  import type { Message, Provider } from "../providers/types.js";
99
99
 
100
100
  function makeProvider(): Provider {
@@ -167,7 +167,7 @@ mock.module("../memory/retriever.js", () => ({
167
167
  injectMemoryRecallAsUserBlock: (msgs: Message[]) => msgs,
168
168
  }));
169
169
 
170
- mock.module("../context/window-manager.js", () => ({
170
+ mock.module("../plugins/defaults/compaction/window-manager.js", () => ({
171
171
  ContextWindowManager: class {
172
172
  constructor() {}
173
173
  updateConfig() {}
@@ -164,7 +164,7 @@ mock.module("../memory/retriever.js", () => ({
164
164
  injectMemoryRecallAsUserBlock: (msgs: Message[]) => msgs,
165
165
  }));
166
166
 
167
- mock.module("../context/window-manager.js", () => ({
167
+ mock.module("../plugins/defaults/compaction/window-manager.js", () => ({
168
168
  ContextWindowManager: class {
169
169
  constructor() {}
170
170
  updateConfig() {}
@@ -319,7 +319,6 @@ describe("classifyConversationError", () => {
319
319
  expect(result.errorCategory).toBe("image_dimensions_too_large");
320
320
  expect(result.retryable).toBe(false);
321
321
  expect(result.userMessage).toContain("image");
322
- expect(result.userMessage).toContain("8000");
323
322
  });
324
323
 
325
324
  it("matches the singular 'image dimension exceeds' phrasing as well", () => {
@@ -333,6 +332,21 @@ describe("classifyConversationError", () => {
333
332
  expect(result.retryable).toBe(false);
334
333
  });
335
334
 
335
+ it("classifies the base64 payload 'exceeds 5 MB maximum' variant as IMAGE_TOO_LARGE (JARVIS-1041)", () => {
336
+ // This is the exact shape that wedged the reporting user: an oversized
337
+ // image nested in a tool_result. It must route to IMAGE_TOO_LARGE so the
338
+ // recovery path fires, not to a retryable PROVIDER_API loop.
339
+ const err = new ProviderError(
340
+ 'Anthropic API error (400): 400 {"type":"error","error":{"type":"invalid_request_error","message":"messages.28.content.1.tool_result.content.1.image.source.base64: image exceeds 5 MB maximum: 7465044 bytes > 5242880 bytes"},"request_id":"req_011CbbFqvxBmDQdhVlqxtAfW"}',
341
+ "anthropic",
342
+ 400,
343
+ );
344
+ const result = classifyConversationError(err, baseCtx);
345
+ expect(result.code).toBe("IMAGE_TOO_LARGE");
346
+ expect(result.errorCategory).toBe("image_dimensions_too_large");
347
+ expect(result.retryable).toBe(false);
348
+ });
349
+
336
350
  it("does not steal generic 400s that happen to mention 'image'", () => {
337
351
  const err = new ProviderError(
338
352
  "invalid request: image source is missing",
@@ -809,6 +809,11 @@ describe("web_search_tool_result structural guard", () => {
809
809
  // contentBlocks property, so it cannot contain nested media.
810
810
  "plugins/defaults/compaction/context-overflow-reducer.ts",
811
811
 
812
+ // Downgrades permanently-unsendable images nested in tool_result.contentBlocks
813
+ // (e.g. an oversized browser screenshot). web_search_tool_result has opaque
814
+ // content with no contentBlocks property, so it cannot hold such an image.
815
+ "daemon/persist-unsendable-image.ts",
816
+
812
817
  // Final orphan-pair safety pass in the Slack transcript renderer.
813
818
  // Server-side block types (`server_tool_use`, `web_search_tool_result`)
814
819
  // are stripped earlier by `buildMessageContentBlocks` and cannot reach
@@ -1,7 +1,7 @@
1
1
  import { describe, expect, test } from "bun:test";
2
2
 
3
- import { createContextSummaryMessage } from "../context/window-manager.js";
4
3
  import { stripMediaPayloadsForRetry } from "../daemon/conversation-media-retry.js";
4
+ import { createContextSummaryMessage } from "../plugins/defaults/compaction/window-manager.js";
5
5
  import type { ContentBlock, Message } from "../providers/types.js";
6
6
 
7
7
  // ---------------------------------------------------------------------------
@@ -185,6 +185,7 @@ function makeQueuedMessage(opts: {
185
185
  requestId: string;
186
186
  content?: string;
187
187
  turnInterfaceContext?: TurnInterfaceContext;
188
+ sourceActorPrincipalId?: string;
188
189
  }): QueuedMessage {
189
190
  return {
190
191
  content: opts.content ?? "follow up",
@@ -194,6 +195,10 @@ function makeQueuedMessage(opts: {
194
195
  metadata: {},
195
196
  sentAt: Date.now(),
196
197
  turnInterfaceContext: opts.turnInterfaceContext,
198
+ sourceActorPrincipalId: opts.sourceActorPrincipalId,
199
+ authContext: opts.sourceActorPrincipalId
200
+ ? ({ actorPrincipalId: opts.sourceActorPrincipalId } as never)
201
+ : undefined,
197
202
  };
198
203
  }
199
204
 
@@ -332,6 +337,7 @@ describe("drainQueue preactivation re-add for host-proxy interfaces", () => {
332
337
  makeQueuedMessage({
333
338
  requestId: "req-web-1",
334
339
  turnInterfaceContext: ifCtx,
340
+ sourceActorPrincipalId: "user-1",
335
341
  }),
336
342
  );
337
343
  const ctx = makeFakeContext({ queue, turnInterfaceContext: ifCtx });
@@ -346,6 +352,39 @@ describe("drainQueue preactivation re-add for host-proxy interfaces", () => {
346
352
  expect(ctx.preactivatedSkillIdCalls).toContain("computer-use");
347
353
  });
348
354
 
355
+ test("drainSingleMessage filters cross-client preactivation by the queued requester, not guardian owner", async () => {
356
+ mockCapabilityClients = [
357
+ { clientId: "owner-macos-client", actorPrincipalId: "owner-user" },
358
+ ];
359
+ const queue = new MessageQueue();
360
+ const ifCtx: TurnInterfaceContext = {
361
+ userMessageInterface: "web",
362
+ assistantMessageInterface: "web",
363
+ };
364
+ queue.push(
365
+ makeQueuedMessage({
366
+ requestId: "req-web-attacker",
367
+ turnInterfaceContext: ifCtx,
368
+ sourceActorPrincipalId: "trusted-contact-user",
369
+ }),
370
+ );
371
+ const ctx = makeFakeContext({ queue, turnInterfaceContext: ifCtx });
372
+ ctx.trustContext = {
373
+ trustClass: "trusted_contact",
374
+ guardianPrincipalId: "owner-user",
375
+ sourceChannel: "vellum",
376
+ };
377
+
378
+ await drainQueue(ctx);
379
+
380
+ expect(ctx.preactivatedSkillIdCalls).not.toContain("computer-use");
381
+ expect(ctx.preactivatedSkillIdCalls).not.toContain("app-control");
382
+ expect(ctx.currentTurnAuthContext?.actorPrincipalId).toBe(
383
+ "trusted-contact-user",
384
+ );
385
+ expect(ctx.currentTurnSourceActorPrincipalId).toBe("trusted-contact-user");
386
+ });
387
+
349
388
  test("drainSingleMessage does NOT re-add 'app-control' for web-sourced message when no capable client is connected", async () => {
350
389
  // mockCapabilityClients remains [] (reset by afterEach from prior test)
351
390
  const queue = new MessageQueue();
@@ -380,6 +419,7 @@ describe("drainQueue preactivation re-add for host-proxy interfaces", () => {
380
419
  makeQueuedMessage({
381
420
  requestId: "req-web-3",
382
421
  turnInterfaceContext: ifCtx,
422
+ sourceActorPrincipalId: "user-1",
383
423
  }),
384
424
  );
385
425
  const ctx = makeFakeContext({ queue, turnInterfaceContext: ifCtx });
@@ -249,7 +249,7 @@ mock.module("../agent/loop.js", () => ({
249
249
  },
250
250
  }));
251
251
 
252
- mock.module("../context/window-manager.js", () => ({
252
+ mock.module("../plugins/defaults/compaction/window-manager.js", () => ({
253
253
  ContextWindowManager: class {
254
254
  constructor() {}
255
255
  updateConfig() {}
@@ -221,7 +221,7 @@ mock.module("../memory/retriever.js", () => ({
221
221
  let maybeCompactCalls: Array<{ force: boolean }> = [];
222
222
  let forceCompactionEnabled = false;
223
223
 
224
- mock.module("../context/window-manager.js", () => ({
224
+ mock.module("../plugins/defaults/compaction/window-manager.js", () => ({
225
225
  ContextWindowManager: class {
226
226
  constructor() {}
227
227
  updateConfig() {}
@@ -262,7 +262,7 @@ mock.module("../memory/retriever.js", () => ({
262
262
  injectMemoryRecallAsUserBlock: (msgs: Message[]) => msgs,
263
263
  }));
264
264
 
265
- mock.module("../context/window-manager.js", () => ({
265
+ mock.module("../plugins/defaults/compaction/window-manager.js", () => ({
266
266
  ContextWindowManager: class {
267
267
  constructor() {}
268
268
  updateConfig() {}
@@ -86,12 +86,14 @@ import {
86
86
  loadSlackChronologicalContext,
87
87
  loadSlackChronologicalMessages,
88
88
  resolveChannelCapabilities,
89
+ resolveTurnInboundActorContext,
89
90
  stripChannelCapabilityContext,
90
91
  stripInjectionsForCompaction,
91
92
  stripNowScratchpad,
92
93
  } from "../daemon/conversation-runtime-assembly.js";
93
94
  import type { SurfaceData, SurfaceType } from "../daemon/message-protocol.js";
94
95
  import { buildPkbReminder } from "../daemon/pkb-reminder-builder.js";
96
+ import type { TrustContext } from "../daemon/trust-context.js";
95
97
  import type { MessageRow } from "../memory/conversation-crud.js";
96
98
  import { getDb } from "../memory/db-connection.js";
97
99
  import { initializeDb } from "../memory/db-init.js";
@@ -1438,6 +1440,75 @@ describe("applyRuntimeInjections with nowScratchpad", () => {
1438
1440
  });
1439
1441
  });
1440
1442
 
1443
+ // ---------------------------------------------------------------------------
1444
+ // resolveTurnInboundActorContext
1445
+ // ---------------------------------------------------------------------------
1446
+
1447
+ describe("resolveTurnInboundActorContext", () => {
1448
+ /**
1449
+ * No trust context means there is no inbound actor to ground the turn on, so
1450
+ * the actor section is suppressed.
1451
+ */
1452
+ test("returns null when there is no trust context", () => {
1453
+ // GIVEN a turn with no trust context
1454
+ // WHEN the inbound actor context is resolved
1455
+ const actorContext = resolveTurnInboundActorContext(undefined, "asst-1");
1456
+
1457
+ // THEN there is no actor context to inject
1458
+ expect(actorContext).toBeNull();
1459
+ });
1460
+
1461
+ /**
1462
+ * Guardian (owner) turns suppress the actor section — the unified turn context
1463
+ * only renders actor fields for non-guardian actors.
1464
+ */
1465
+ test("returns null on guardian turns", () => {
1466
+ // GIVEN a guardian trust context (no requester chat id, so the direct
1467
+ // projection branch is taken)
1468
+ const trustContext: TrustContext = {
1469
+ sourceChannel: "vellum",
1470
+ trustClass: "guardian",
1471
+ requesterDisplayName: "Alice",
1472
+ };
1473
+
1474
+ // WHEN the inbound actor context is resolved
1475
+ const actorContext = resolveTurnInboundActorContext(trustContext, "asst-1");
1476
+
1477
+ // THEN the actor section is suppressed for the owner
1478
+ expect(actorContext).toBeNull();
1479
+ });
1480
+
1481
+ /**
1482
+ * A non-guardian trust context without the identity fields needed for the
1483
+ * unified actor-trust lookup is projected directly into the actor context.
1484
+ */
1485
+ test("projects a non-guardian trust context directly", () => {
1486
+ // GIVEN a trusted-contact trust context lacking requester chat/user ids
1487
+ const trustContext: TrustContext = {
1488
+ sourceChannel: "telegram",
1489
+ trustClass: "trusted_contact",
1490
+ requesterIdentifier: "@bob_handle",
1491
+ requesterDisplayName: "Bob",
1492
+ requesterSenderDisplayName: "Bobby",
1493
+ };
1494
+
1495
+ // WHEN the inbound actor context is resolved
1496
+ const actorContext = resolveTurnInboundActorContext(trustContext, "asst-1");
1497
+
1498
+ // THEN the trust context is projected into the model-facing actor context
1499
+ expect(actorContext).toEqual({
1500
+ sourceChannel: "telegram",
1501
+ canonicalActorIdentity: null,
1502
+ actorIdentifier: "@bob_handle",
1503
+ actorDisplayName: "Bob",
1504
+ actorSenderDisplayName: "Bobby",
1505
+ actorMemberDisplayName: undefined,
1506
+ trustClass: "trusted_contact",
1507
+ guardianIdentity: undefined,
1508
+ });
1509
+ });
1510
+ });
1511
+
1441
1512
  // ---------------------------------------------------------------------------
1442
1513
  // buildUnifiedTurnContextBlock
1443
1514
  // ---------------------------------------------------------------------------
@@ -153,7 +153,7 @@ mock.module("../memory/retriever.js", () => ({
153
153
  injectMemoryRecallAsUserBlock: (msgs: Message[]) => msgs,
154
154
  }));
155
155
 
156
- mock.module("../context/window-manager.js", () => ({
156
+ mock.module("../plugins/defaults/compaction/window-manager.js", () => ({
157
157
  ContextWindowManager: class {
158
158
  constructor() {}
159
159
  updateConfig() {}
@@ -154,7 +154,7 @@ mock.module("../memory/retriever.js", () => ({
154
154
  injectMemoryRecallAsUserBlock: (msgs: Message[]) => msgs,
155
155
  }));
156
156
 
157
- mock.module("../context/window-manager.js", () => ({
157
+ mock.module("../plugins/defaults/compaction/window-manager.js", () => ({
158
158
  ContextWindowManager: class {
159
159
  constructor() {}
160
160
  updateConfig() {}
@@ -170,7 +170,7 @@ mock.module("../memory/retriever.js", () => ({
170
170
  injectMemoryRecallAsUserBlock: (msgs: Message[]) => msgs,
171
171
  }));
172
172
 
173
- mock.module("../context/window-manager.js", () => ({
173
+ mock.module("../plugins/defaults/compaction/window-manager.js", () => ({
174
174
  ContextWindowManager: class {
175
175
  constructor() {}
176
176
  updateConfig() {}