@makefinks/daemon 0.1.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.
- package/LICENSE +21 -0
- package/README.md +126 -0
- package/dist/cli.js +22 -0
- package/package.json +79 -0
- package/src/ai/agent-turn-runner.ts +130 -0
- package/src/ai/daemon-ai.ts +403 -0
- package/src/ai/exa-client.ts +21 -0
- package/src/ai/exa-fetch-cache.ts +104 -0
- package/src/ai/model-config.ts +99 -0
- package/src/ai/sanitize-messages.ts +83 -0
- package/src/ai/system-prompt.ts +363 -0
- package/src/ai/tools/fetch-urls.ts +187 -0
- package/src/ai/tools/grounding-manager.ts +94 -0
- package/src/ai/tools/index.ts +52 -0
- package/src/ai/tools/read-file.ts +100 -0
- package/src/ai/tools/render-url.ts +275 -0
- package/src/ai/tools/run-bash.ts +224 -0
- package/src/ai/tools/subagents.ts +195 -0
- package/src/ai/tools/todo-manager.ts +150 -0
- package/src/ai/tools/web-search.ts +91 -0
- package/src/app/App.tsx +711 -0
- package/src/app/components/AppOverlays.tsx +131 -0
- package/src/app/components/AvatarLayer.tsx +51 -0
- package/src/app/components/ConversationPane.tsx +476 -0
- package/src/avatar/DaemonAvatarRenderable.ts +343 -0
- package/src/avatar/daemon-avatar-rig.ts +1165 -0
- package/src/avatar-preview.ts +186 -0
- package/src/cli.ts +26 -0
- package/src/components/ApiKeyInput.tsx +99 -0
- package/src/components/ApiKeyStep.tsx +95 -0
- package/src/components/ApprovalPicker.tsx +109 -0
- package/src/components/ContentBlockView.tsx +141 -0
- package/src/components/DaemonText.tsx +34 -0
- package/src/components/DeviceMenu.tsx +166 -0
- package/src/components/GroundingBadge.tsx +21 -0
- package/src/components/GroundingMenu.tsx +310 -0
- package/src/components/HotkeysPane.tsx +115 -0
- package/src/components/InlineStatusIndicator.tsx +106 -0
- package/src/components/ModelMenu.tsx +411 -0
- package/src/components/OnboardingOverlay.tsx +446 -0
- package/src/components/ProviderMenu.tsx +177 -0
- package/src/components/SessionMenu.tsx +297 -0
- package/src/components/SettingsMenu.tsx +291 -0
- package/src/components/StatusBar.tsx +126 -0
- package/src/components/TokenUsageDisplay.tsx +92 -0
- package/src/components/ToolCallView.tsx +113 -0
- package/src/components/TypingInputBar.tsx +131 -0
- package/src/components/tool-layouts/components.tsx +120 -0
- package/src/components/tool-layouts/defaults.ts +9 -0
- package/src/components/tool-layouts/index.ts +22 -0
- package/src/components/tool-layouts/layouts/bash.ts +110 -0
- package/src/components/tool-layouts/layouts/grounding.tsx +98 -0
- package/src/components/tool-layouts/layouts/index.ts +8 -0
- package/src/components/tool-layouts/layouts/read-file.ts +59 -0
- package/src/components/tool-layouts/layouts/subagent.tsx +118 -0
- package/src/components/tool-layouts/layouts/system-info.ts +8 -0
- package/src/components/tool-layouts/layouts/todo.tsx +139 -0
- package/src/components/tool-layouts/layouts/url-tools.ts +220 -0
- package/src/components/tool-layouts/layouts/web-search.ts +110 -0
- package/src/components/tool-layouts/registry.ts +17 -0
- package/src/components/tool-layouts/types.ts +94 -0
- package/src/hooks/daemon-event-handlers.ts +944 -0
- package/src/hooks/keyboard-handlers.ts +399 -0
- package/src/hooks/menu-navigation.ts +147 -0
- package/src/hooks/use-app-audio-devices-loader.ts +71 -0
- package/src/hooks/use-app-callbacks.ts +202 -0
- package/src/hooks/use-app-context-builder.ts +159 -0
- package/src/hooks/use-app-display-state.ts +162 -0
- package/src/hooks/use-app-menus.ts +51 -0
- package/src/hooks/use-app-model-pricing-loader.ts +45 -0
- package/src/hooks/use-app-model.ts +123 -0
- package/src/hooks/use-app-openrouter-models-loader.ts +44 -0
- package/src/hooks/use-app-openrouter-provider-loader.ts +35 -0
- package/src/hooks/use-app-preferences-bootstrap.ts +212 -0
- package/src/hooks/use-app-sessions.ts +105 -0
- package/src/hooks/use-app-settings.ts +62 -0
- package/src/hooks/use-conversation-manager.ts +163 -0
- package/src/hooks/use-copy-on-select.ts +50 -0
- package/src/hooks/use-daemon-events.ts +396 -0
- package/src/hooks/use-daemon-keyboard.ts +397 -0
- package/src/hooks/use-grounding.ts +46 -0
- package/src/hooks/use-input-history.ts +92 -0
- package/src/hooks/use-menu-keyboard.ts +93 -0
- package/src/hooks/use-playwright-notification.ts +23 -0
- package/src/hooks/use-reasoning-animation.ts +97 -0
- package/src/hooks/use-response-timer.ts +55 -0
- package/src/hooks/use-tool-approval.tsx +202 -0
- package/src/hooks/use-typing-mode.ts +137 -0
- package/src/hooks/use-voice-dependencies-notification.ts +37 -0
- package/src/index.tsx +48 -0
- package/src/scripts/setup-browsers.ts +42 -0
- package/src/state/app-context.tsx +160 -0
- package/src/state/daemon-events.ts +67 -0
- package/src/state/daemon-state.ts +493 -0
- package/src/state/migrations/001-init.ts +33 -0
- package/src/state/migrations/index.ts +8 -0
- package/src/state/model-history-store.ts +45 -0
- package/src/state/runtime-context.ts +21 -0
- package/src/state/session-store.ts +359 -0
- package/src/types/index.ts +405 -0
- package/src/types/theme.ts +52 -0
- package/src/ui/constants.ts +157 -0
- package/src/utils/clipboard.ts +89 -0
- package/src/utils/debug-logger.ts +69 -0
- package/src/utils/formatters.ts +242 -0
- package/src/utils/js-rendering.ts +77 -0
- package/src/utils/markdown-tables.ts +234 -0
- package/src/utils/model-metadata.ts +191 -0
- package/src/utils/openrouter-endpoints.ts +212 -0
- package/src/utils/openrouter-models.ts +205 -0
- package/src/utils/openrouter-pricing.ts +59 -0
- package/src/utils/openrouter-reported-cost.ts +16 -0
- package/src/utils/paste.ts +33 -0
- package/src/utils/preferences.ts +289 -0
- package/src/utils/text-fragment.ts +39 -0
- package/src/utils/tool-output-preview.ts +250 -0
- package/src/utils/voice-dependencies.ts +107 -0
- package/src/utils/workspace-manager.ts +85 -0
- package/src/voice/audio-recorder.ts +579 -0
- package/src/voice/mic-level.ts +35 -0
- package/src/voice/tts/openai-tts-stream.ts +222 -0
- package/src/voice/tts/speech-controller.ts +64 -0
- package/src/voice/tts/tts-player.ts +257 -0
- package/src/voice/voice-input-controller.ts +96 -0
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FrameBufferRenderable,
|
|
3
|
+
RGBA,
|
|
4
|
+
TextAttributes,
|
|
5
|
+
OptimizedBuffer,
|
|
6
|
+
type CliRenderer,
|
|
7
|
+
} from "@opentui/core";
|
|
8
|
+
import { SuperSampleType, ThreeCliRenderer } from "@opentui/core/3d";
|
|
9
|
+
import {
|
|
10
|
+
createDaemonRig,
|
|
11
|
+
type DaemonColorTheme,
|
|
12
|
+
type DaemonRig,
|
|
13
|
+
type ToolCategory,
|
|
14
|
+
} from "./daemon-avatar-rig";
|
|
15
|
+
|
|
16
|
+
export type { ToolCategory } from "./daemon-avatar-rig";
|
|
17
|
+
|
|
18
|
+
export class DaemonAvatarRenderable extends FrameBufferRenderable {
|
|
19
|
+
private three: ThreeCliRenderer | null = null;
|
|
20
|
+
private rig: DaemonRig | null = null;
|
|
21
|
+
private renderBuffer: OptimizedBuffer | null = null;
|
|
22
|
+
private lastAppliedAspectRatio: number | null = null;
|
|
23
|
+
|
|
24
|
+
private initStarted = false;
|
|
25
|
+
private initError: Error | null = null;
|
|
26
|
+
private renderInFlight = false;
|
|
27
|
+
private destroyedSelf = false;
|
|
28
|
+
|
|
29
|
+
private lastFrameTimeMs = performance.now();
|
|
30
|
+
private pendingTheme: DaemonColorTheme | null = null;
|
|
31
|
+
private pendingIntensity: { value: number; immediate: boolean } | null = null;
|
|
32
|
+
private pendingAudioLevel: { value: number; immediate: boolean } | null = null;
|
|
33
|
+
|
|
34
|
+
private getDesiredAspectRatio(width: number, height: number): number {
|
|
35
|
+
if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) return 1;
|
|
36
|
+
|
|
37
|
+
const cliRenderer = this._ctx as unknown as CliRenderer;
|
|
38
|
+
|
|
39
|
+
// Terminal cells are usually not square. If we know the terminal pixel resolution,
|
|
40
|
+
// derive a per-cell width/height ratio; otherwise fall back to the same 0.5
|
|
41
|
+
// heuristic used by @opentui/core's ThreeCliRenderer.
|
|
42
|
+
let cellAspectRatio = 0.5;
|
|
43
|
+
const resolution = cliRenderer.resolution;
|
|
44
|
+
if (resolution) {
|
|
45
|
+
const termW = cliRenderer.terminalWidth;
|
|
46
|
+
const termH = cliRenderer.terminalHeight;
|
|
47
|
+
if (termW > 0 && termH > 0 && resolution.width > 0 && resolution.height > 0) {
|
|
48
|
+
const cellW = resolution.width / termW;
|
|
49
|
+
const cellH = resolution.height / termH;
|
|
50
|
+
const derived = cellW / cellH;
|
|
51
|
+
if (Number.isFinite(derived) && derived > 0) {
|
|
52
|
+
cellAspectRatio = derived;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const aspect = (width / height) * cellAspectRatio;
|
|
58
|
+
if (!Number.isFinite(aspect) || aspect <= 0) return 1;
|
|
59
|
+
return aspect;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private updateCameraSettings(): void {
|
|
63
|
+
if (!this.rig) return;
|
|
64
|
+
|
|
65
|
+
// 1. Aspect Ratio
|
|
66
|
+
const desiredAspect = this.getDesiredAspectRatio(this.frameBuffer.width, this.frameBuffer.height);
|
|
67
|
+
if (
|
|
68
|
+
this.lastAppliedAspectRatio === null ||
|
|
69
|
+
Math.abs(this.lastAppliedAspectRatio - desiredAspect) >= 0.001
|
|
70
|
+
) {
|
|
71
|
+
this.rig.camera.aspect = desiredAspect;
|
|
72
|
+
this.rig.camera.updateProjectionMatrix();
|
|
73
|
+
this.lastAppliedAspectRatio = desiredAspect;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// 2. Dynamic Z-Distance (Scaling)
|
|
77
|
+
// "Sensibly bigger if we have more space and smaller when theres less space"
|
|
78
|
+
// We use height as the primary driver for scale in the landscape terminal environment.
|
|
79
|
+
// Base height: 30 rows. Base Z: 5.0 (Closer default to fix "small/pixelated" look).
|
|
80
|
+
const h = this.frameBuffer.height;
|
|
81
|
+
const baseHeight = 30;
|
|
82
|
+
const baseZ = 5.0;
|
|
83
|
+
|
|
84
|
+
// Power factor determines sensitivity. 0.1 is subtle.
|
|
85
|
+
let scaleFactor = Math.pow(baseHeight / Math.max(10, h), 0.1);
|
|
86
|
+
|
|
87
|
+
// Clamp Z to prevent extreme clipping or disappearing
|
|
88
|
+
// Min Z=4.0 (Very close)
|
|
89
|
+
// Max Z=12.0 (Far away)
|
|
90
|
+
let targetZ = baseZ * scaleFactor;
|
|
91
|
+
targetZ = Math.max(4.0, Math.min(12.0, targetZ));
|
|
92
|
+
|
|
93
|
+
this.rig.camera.position.z = targetZ;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private startInitIfNeeded(): void {
|
|
97
|
+
if (this.initStarted || this.initError || this.destroyedSelf) return;
|
|
98
|
+
this.initStarted = true;
|
|
99
|
+
|
|
100
|
+
void this.initThree().catch((err: unknown) => {
|
|
101
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
102
|
+
this.initError = error;
|
|
103
|
+
this._ctx.requestRender();
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private async initThree(): Promise<void> {
|
|
108
|
+
const cliRenderer = this._ctx as unknown as CliRenderer;
|
|
109
|
+
|
|
110
|
+
const three = new ThreeCliRenderer(cliRenderer, {
|
|
111
|
+
width: this.frameBuffer.width,
|
|
112
|
+
height: this.frameBuffer.height,
|
|
113
|
+
alpha: true,
|
|
114
|
+
backgroundColor: RGBA.fromValues(0, 0, 0, 0),
|
|
115
|
+
superSample: SuperSampleType.GPU,
|
|
116
|
+
autoResize: false,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
await three.init();
|
|
120
|
+
if (this.destroyedSelf) {
|
|
121
|
+
three.destroy();
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const rig = createDaemonRig({
|
|
126
|
+
aspectRatio: this.getDesiredAspectRatio(this.frameBuffer.width, this.frameBuffer.height),
|
|
127
|
+
});
|
|
128
|
+
three.setActiveCamera(rig.camera);
|
|
129
|
+
|
|
130
|
+
this.three = three;
|
|
131
|
+
this.rig = rig;
|
|
132
|
+
if (this.pendingTheme) {
|
|
133
|
+
this.rig.setColors(this.pendingTheme);
|
|
134
|
+
}
|
|
135
|
+
if (this.pendingIntensity) {
|
|
136
|
+
this.rig.setIntensity(this.pendingIntensity.value, { immediate: this.pendingIntensity.immediate });
|
|
137
|
+
}
|
|
138
|
+
if (this.pendingAudioLevel) {
|
|
139
|
+
this.rig.setAudioLevel(this.pendingAudioLevel.value, { immediate: this.pendingAudioLevel.immediate });
|
|
140
|
+
}
|
|
141
|
+
this.renderBuffer = OptimizedBuffer.create(
|
|
142
|
+
this.frameBuffer.width,
|
|
143
|
+
this.frameBuffer.height,
|
|
144
|
+
cliRenderer.widthMethod,
|
|
145
|
+
{
|
|
146
|
+
respectAlpha: true,
|
|
147
|
+
id: `${this.frameBuffer.id}-render`,
|
|
148
|
+
}
|
|
149
|
+
);
|
|
150
|
+
this.updateCameraSettings();
|
|
151
|
+
this._ctx.requestRender();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
private kickRenderFrame(): void {
|
|
155
|
+
if (!this.three || !this.rig || !this.renderBuffer || this.destroyedSelf) return;
|
|
156
|
+
if (this.renderInFlight) return;
|
|
157
|
+
|
|
158
|
+
this.updateCameraSettings();
|
|
159
|
+
|
|
160
|
+
const renderBuffer = this.renderBuffer;
|
|
161
|
+
|
|
162
|
+
const now = performance.now();
|
|
163
|
+
let deltaS = (now - this.lastFrameTimeMs) / 1000;
|
|
164
|
+
this.lastFrameTimeMs = now;
|
|
165
|
+
// Avoid "time compounding" when the render loop calls us multiple times within the
|
|
166
|
+
// same timer tick (some environments have coarse `performance.now()` resolution).
|
|
167
|
+
// A 0 delta should mean "no time advanced", not "assume 60fps".
|
|
168
|
+
if (!Number.isFinite(deltaS) || deltaS < 0) deltaS = 0;
|
|
169
|
+
deltaS = Math.min(deltaS, 0.1);
|
|
170
|
+
|
|
171
|
+
// ThreeCliRenderer does not guarantee it overwrites every cell each frame when alpha
|
|
172
|
+
// is enabled; if we don't clear, old pixels can "stick" (most visible on thin,
|
|
173
|
+
// additive elements like the rotating rings). We clear a *back buffer* to avoid
|
|
174
|
+
// blanking the currently displayed frame while drawScene is in-flight.
|
|
175
|
+
renderBuffer.clear(RGBA.fromValues(0, 0, 0, 0));
|
|
176
|
+
|
|
177
|
+
this.rig.update(deltaS);
|
|
178
|
+
|
|
179
|
+
this.renderInFlight = true;
|
|
180
|
+
void this.three
|
|
181
|
+
.drawScene(this.rig.scene, renderBuffer, deltaS)
|
|
182
|
+
.then(() => {
|
|
183
|
+
if (this.destroyedSelf) return;
|
|
184
|
+
|
|
185
|
+
// Present: copy rendered back buffer into the displayed framebuffer.
|
|
186
|
+
// (FrameBufferRenderable always draws `this.frameBuffer`.)
|
|
187
|
+
this.frameBuffer.clear(RGBA.fromValues(0, 0, 0, 0));
|
|
188
|
+
this.frameBuffer.drawFrameBuffer(0, 0, renderBuffer);
|
|
189
|
+
|
|
190
|
+
this.renderInFlight = false;
|
|
191
|
+
this._ctx.requestRender();
|
|
192
|
+
})
|
|
193
|
+
.catch((err: unknown) => {
|
|
194
|
+
this.renderInFlight = false;
|
|
195
|
+
this.initError = err instanceof Error ? err : new Error(String(err));
|
|
196
|
+
this._ctx.requestRender();
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
protected override onResize(width: number, height: number): void {
|
|
201
|
+
super.onResize(width, height);
|
|
202
|
+
if (this.three) {
|
|
203
|
+
this.three.setSize(width, height, true);
|
|
204
|
+
this.updateCameraSettings();
|
|
205
|
+
}
|
|
206
|
+
if (this.renderBuffer) {
|
|
207
|
+
this.renderBuffer.resize(width, height);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
protected override renderSelf(buffer: OptimizedBuffer): void {
|
|
212
|
+
if (!this.visible || this.isDestroyed) return;
|
|
213
|
+
|
|
214
|
+
this.startInitIfNeeded();
|
|
215
|
+
|
|
216
|
+
if (this.initError) {
|
|
217
|
+
const fb = this.frameBuffer;
|
|
218
|
+
const w = fb.width;
|
|
219
|
+
const h = fb.height;
|
|
220
|
+
fb.clear(RGBA.fromValues(0, 0, 0, 0));
|
|
221
|
+
const msg = "SYSTEM FAILURE";
|
|
222
|
+
fb.drawText(
|
|
223
|
+
msg,
|
|
224
|
+
Math.max(0, (w - msg.length) / 2),
|
|
225
|
+
h / 2,
|
|
226
|
+
RGBA.fromInts(255, 50, 50, 255),
|
|
227
|
+
RGBA.fromInts(0, 0, 0, 0),
|
|
228
|
+
TextAttributes.BOLD
|
|
229
|
+
);
|
|
230
|
+
} else if (!this.three || !this.rig) {
|
|
231
|
+
const fb = this.frameBuffer;
|
|
232
|
+
const w = fb.width;
|
|
233
|
+
const h = fb.height;
|
|
234
|
+
fb.clear(RGBA.fromValues(0, 0, 0, 0));
|
|
235
|
+
|
|
236
|
+
const glyph = w >= 18 ? "⟡ SUMMONING ⟡" : "SUMMONING";
|
|
237
|
+
const gx = Math.max(0, Math.floor(w / 2) - Math.floor(glyph.length / 2));
|
|
238
|
+
const gy = Math.floor(h / 2);
|
|
239
|
+
fb.drawText(
|
|
240
|
+
glyph,
|
|
241
|
+
gx,
|
|
242
|
+
Math.max(0, Math.min(h - 1, gy)),
|
|
243
|
+
RGBA.fromInts(180, 255, 245, 230),
|
|
244
|
+
RGBA.fromInts(0, 0, 0, 0),
|
|
245
|
+
TextAttributes.DIM
|
|
246
|
+
);
|
|
247
|
+
if (h >= 2) {
|
|
248
|
+
fb.drawText(
|
|
249
|
+
"DAEMON",
|
|
250
|
+
Math.max(0, Math.floor(w / 2) - 3),
|
|
251
|
+
Math.max(0, Math.min(h - 1, gy + 1)),
|
|
252
|
+
RGBA.fromInts(130, 190, 255, 200),
|
|
253
|
+
RGBA.fromInts(0, 0, 0, 0),
|
|
254
|
+
TextAttributes.BOLD
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
} else {
|
|
258
|
+
this.kickRenderFrame();
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
super.renderSelf(buffer);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
protected override destroySelf(): void {
|
|
265
|
+
this.destroyedSelf = true;
|
|
266
|
+
this.rig?.dispose();
|
|
267
|
+
this.rig = null;
|
|
268
|
+
this.three?.destroy();
|
|
269
|
+
this.three = null;
|
|
270
|
+
this.renderBuffer?.destroy();
|
|
271
|
+
this.renderBuffer = null;
|
|
272
|
+
super.destroySelf();
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Set the color theme for the DAEMON avatar.
|
|
277
|
+
* Colors will smoothly transition to the new theme.
|
|
278
|
+
*/
|
|
279
|
+
public setColors(theme: DaemonColorTheme): void {
|
|
280
|
+
this.pendingTheme = theme;
|
|
281
|
+
if (this.rig) {
|
|
282
|
+
this.rig.setColors(theme);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Set animation intensity (0 = idle, 1 = responding/active).
|
|
288
|
+
* Higher intensity causes faster, more dramatic animations.
|
|
289
|
+
*/
|
|
290
|
+
public setIntensity(intensity: number, options?: { immediate?: boolean }): void {
|
|
291
|
+
this.pendingIntensity = { value: intensity, immediate: options?.immediate ?? false };
|
|
292
|
+
if (this.rig) {
|
|
293
|
+
this.rig.setIntensity(intensity, options);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Set real-time audio level (0 = silence, 1 = loud).
|
|
299
|
+
* Used for reactive size/opacity without changing spin speed.
|
|
300
|
+
*/
|
|
301
|
+
public setAudioLevel(level: number, options?: { immediate?: boolean }): void {
|
|
302
|
+
this.pendingAudioLevel = { value: level, immediate: options?.immediate ?? false };
|
|
303
|
+
if (this.rig) {
|
|
304
|
+
this.rig.setAudioLevel(level, options);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
public setToolActive(active: boolean, category?: ToolCategory): void {
|
|
309
|
+
if (this.rig) {
|
|
310
|
+
this.rig.setToolActive(active, category);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
public triggerToolFlash(category?: ToolCategory): void {
|
|
315
|
+
if (this.rig) {
|
|
316
|
+
this.rig.triggerToolFlash(category);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
public triggerToolComplete(): void {
|
|
321
|
+
if (this.rig) {
|
|
322
|
+
this.rig.triggerToolComplete();
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
public setReasoningMode(active: boolean): void {
|
|
327
|
+
if (this.rig) {
|
|
328
|
+
this.rig.setReasoningMode(active);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
public setTypingMode(active: boolean): void {
|
|
333
|
+
if (this.rig) {
|
|
334
|
+
this.rig.setTypingMode(active);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
public triggerTypingPulse(): void {
|
|
339
|
+
if (this.rig) {
|
|
340
|
+
this.rig.triggerTypingPulse();
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|