@hybridaione/hybridclaw 0.2.2 → 0.2.6
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/.github/workflows/ci.yml +70 -0
- package/.husky/pre-commit +1 -0
- package/CHANGELOG.md +85 -0
- package/CONTRIBUTING.md +33 -0
- package/README.md +41 -16
- package/SECURITY.md +17 -0
- package/biome.json +35 -0
- package/config.example.json +71 -8
- package/container/package-lock.json +2 -2
- package/container/package.json +1 -1
- package/container/src/approval-policy.ts +1303 -0
- package/container/src/browser-tools.ts +431 -136
- package/container/src/extensions.ts +36 -12
- package/container/src/hybridai-client.ts +34 -13
- package/container/src/index.ts +451 -109
- package/container/src/ipc.ts +5 -3
- package/container/src/token-usage.ts +20 -10
- package/container/src/tools.ts +599 -225
- package/container/src/types.ts +32 -2
- package/container/src/web-fetch.ts +89 -32
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +10 -2
- package/dist/agent.js.map +1 -1
- package/dist/audit-cli.d.ts.map +1 -1
- package/dist/audit-cli.js +4 -2
- package/dist/audit-cli.js.map +1 -1
- package/dist/audit-events.d.ts.map +1 -1
- package/dist/audit-events.js +53 -3
- package/dist/audit-events.js.map +1 -1
- package/dist/audit-trail.d.ts.map +1 -1
- package/dist/audit-trail.js +17 -8
- package/dist/audit-trail.js.map +1 -1
- package/dist/channels/discord/attachments.d.ts.map +1 -1
- package/dist/channels/discord/attachments.js +14 -7
- package/dist/channels/discord/attachments.js.map +1 -1
- package/dist/channels/discord/debounce.d.ts +9 -0
- package/dist/channels/discord/debounce.d.ts.map +1 -0
- package/dist/channels/discord/debounce.js +20 -0
- package/dist/channels/discord/debounce.js.map +1 -0
- package/dist/channels/discord/delivery.d.ts +4 -1
- package/dist/channels/discord/delivery.d.ts.map +1 -1
- package/dist/channels/discord/delivery.js +19 -3
- package/dist/channels/discord/delivery.js.map +1 -1
- package/dist/channels/discord/human-delay.d.ts +16 -0
- package/dist/channels/discord/human-delay.d.ts.map +1 -0
- package/dist/channels/discord/human-delay.js +29 -0
- package/dist/channels/discord/human-delay.js.map +1 -0
- package/dist/channels/discord/inbound.d.ts +4 -0
- package/dist/channels/discord/inbound.d.ts.map +1 -1
- package/dist/channels/discord/inbound.js +45 -4
- package/dist/channels/discord/inbound.js.map +1 -1
- package/dist/channels/discord/mentions.d.ts.map +1 -1
- package/dist/channels/discord/mentions.js +16 -4
- package/dist/channels/discord/mentions.js.map +1 -1
- package/dist/channels/discord/presence.d.ts +33 -0
- package/dist/channels/discord/presence.d.ts.map +1 -0
- package/dist/channels/discord/presence.js +111 -0
- package/dist/channels/discord/presence.js.map +1 -0
- package/dist/channels/discord/rate-limiter.d.ts +14 -0
- package/dist/channels/discord/rate-limiter.d.ts.map +1 -0
- package/dist/channels/discord/rate-limiter.js +49 -0
- package/dist/channels/discord/rate-limiter.js.map +1 -0
- package/dist/channels/discord/reactions.d.ts +38 -0
- package/dist/channels/discord/reactions.d.ts.map +1 -0
- package/dist/channels/discord/reactions.js +151 -0
- package/dist/channels/discord/reactions.js.map +1 -0
- package/dist/channels/discord/runtime.d.ts +6 -3
- package/dist/channels/discord/runtime.d.ts.map +1 -1
- package/dist/channels/discord/runtime.js +621 -125
- package/dist/channels/discord/runtime.js.map +1 -1
- package/dist/channels/discord/stream.d.ts +4 -1
- package/dist/channels/discord/stream.d.ts.map +1 -1
- package/dist/channels/discord/stream.js +16 -8
- package/dist/channels/discord/stream.js.map +1 -1
- package/dist/channels/discord/tool-actions.d.ts.map +1 -1
- package/dist/channels/discord/tool-actions.js +24 -12
- package/dist/channels/discord/tool-actions.js.map +1 -1
- package/dist/channels/discord/typing.d.ts +15 -0
- package/dist/channels/discord/typing.d.ts.map +1 -0
- package/dist/channels/discord/typing.js +106 -0
- package/dist/channels/discord/typing.js.map +1 -0
- package/dist/chunk.d.ts.map +1 -1
- package/dist/chunk.js +4 -2
- package/dist/chunk.js.map +1 -1
- package/dist/cli.js +47 -22
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +19 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +103 -18
- package/dist/config.js.map +1 -1
- package/dist/container-runner.d.ts.map +1 -1
- package/dist/container-runner.js +58 -26
- package/dist/container-runner.js.map +1 -1
- package/dist/container-setup.d.ts.map +1 -1
- package/dist/container-setup.js +10 -9
- package/dist/container-setup.js.map +1 -1
- package/dist/conversation.d.ts +2 -2
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +1 -1
- package/dist/conversation.js.map +1 -1
- package/dist/db.d.ts +118 -2
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +1568 -50
- package/dist/db.js.map +1 -1
- package/dist/delegation-manager.d.ts.map +1 -1
- package/dist/delegation-manager.js +3 -2
- package/dist/delegation-manager.js.map +1 -1
- package/dist/gateway-client.d.ts +2 -2
- package/dist/gateway-client.d.ts.map +1 -1
- package/dist/gateway-client.js +10 -4
- package/dist/gateway-client.js.map +1 -1
- package/dist/gateway-service.d.ts +3 -3
- package/dist/gateway-service.d.ts.map +1 -1
- package/dist/gateway-service.js +563 -73
- package/dist/gateway-service.js.map +1 -1
- package/dist/gateway-types.d.ts +24 -0
- package/dist/gateway-types.d.ts.map +1 -1
- package/dist/gateway-types.js.map +1 -1
- package/dist/gateway.js +179 -24
- package/dist/gateway.js.map +1 -1
- package/dist/health.d.ts.map +1 -1
- package/dist/health.js +20 -10
- package/dist/health.js.map +1 -1
- package/dist/heartbeat.d.ts +4 -0
- package/dist/heartbeat.d.ts.map +1 -1
- package/dist/heartbeat.js +48 -20
- package/dist/heartbeat.js.map +1 -1
- package/dist/hybridai-bots.d.ts.map +1 -1
- package/dist/hybridai-bots.js +4 -2
- package/dist/hybridai-bots.js.map +1 -1
- package/dist/instruction-approval-audit.d.ts.map +1 -1
- package/dist/instruction-approval-audit.js.map +1 -1
- package/dist/instruction-integrity.d.ts.map +1 -1
- package/dist/instruction-integrity.js +8 -2
- package/dist/instruction-integrity.js.map +1 -1
- package/dist/ipc.d.ts.map +1 -1
- package/dist/ipc.js +6 -1
- package/dist/ipc.js.map +1 -1
- package/dist/logger.js.map +1 -1
- package/dist/memory-consolidation.d.ts +17 -0
- package/dist/memory-consolidation.d.ts.map +1 -0
- package/dist/memory-consolidation.js +25 -0
- package/dist/memory-consolidation.js.map +1 -0
- package/dist/memory-service.d.ts +200 -0
- package/dist/memory-service.d.ts.map +1 -0
- package/dist/memory-service.js +294 -0
- package/dist/memory-service.js.map +1 -0
- package/dist/mount-security.d.ts.map +1 -1
- package/dist/mount-security.js +31 -7
- package/dist/mount-security.js.map +1 -1
- package/dist/observability-ingest.d.ts.map +1 -1
- package/dist/observability-ingest.js +32 -11
- package/dist/observability-ingest.js.map +1 -1
- package/dist/onboarding.d.ts.map +1 -1
- package/dist/onboarding.js +32 -9
- package/dist/onboarding.js.map +1 -1
- package/dist/proactive-policy.d.ts.map +1 -1
- package/dist/proactive-policy.js +2 -1
- package/dist/proactive-policy.js.map +1 -1
- package/dist/prompt-hooks.d.ts.map +1 -1
- package/dist/prompt-hooks.js +9 -7
- package/dist/prompt-hooks.js.map +1 -1
- package/dist/runtime-config.d.ts +98 -1
- package/dist/runtime-config.d.ts.map +1 -1
- package/dist/runtime-config.js +477 -23
- package/dist/runtime-config.js.map +1 -1
- package/dist/scheduled-task-runner.d.ts +1 -0
- package/dist/scheduled-task-runner.d.ts.map +1 -1
- package/dist/scheduled-task-runner.js +29 -10
- package/dist/scheduled-task-runner.js.map +1 -1
- package/dist/scheduler.d.ts +43 -4
- package/dist/scheduler.d.ts.map +1 -1
- package/dist/scheduler.js +530 -56
- package/dist/scheduler.js.map +1 -1
- package/dist/session-export.d.ts +26 -0
- package/dist/session-export.d.ts.map +1 -0
- package/dist/session-export.js +149 -0
- package/dist/session-export.js.map +1 -0
- package/dist/session-maintenance.d.ts.map +1 -1
- package/dist/session-maintenance.js +75 -13
- package/dist/session-maintenance.js.map +1 -1
- package/dist/session-transcripts.d.ts.map +1 -1
- package/dist/session-transcripts.js.map +1 -1
- package/dist/side-effects.d.ts.map +1 -1
- package/dist/side-effects.js +14 -2
- package/dist/side-effects.js.map +1 -1
- package/dist/skills-guard.d.ts.map +1 -1
- package/dist/skills-guard.js +893 -130
- package/dist/skills-guard.js.map +1 -1
- package/dist/skills.d.ts +5 -0
- package/dist/skills.d.ts.map +1 -1
- package/dist/skills.js +29 -15
- package/dist/skills.js.map +1 -1
- package/dist/token-efficiency.d.ts.map +1 -1
- package/dist/token-efficiency.js.map +1 -1
- package/dist/tui.js +92 -11
- package/dist/tui.js.map +1 -1
- package/dist/types.d.ts +146 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +24 -1
- package/dist/types.js.map +1 -1
- package/dist/update.d.ts.map +1 -1
- package/dist/update.js +42 -14
- package/dist/update.js.map +1 -1
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +49 -9
- package/dist/workspace.js.map +1 -1
- package/docs/chat.html +9 -3
- package/docs/index.html +37 -13
- package/package.json +8 -2
- package/src/agent.ts +16 -3
- package/src/audit-cli.ts +44 -16
- package/src/audit-events.ts +69 -5
- package/src/audit-trail.ts +41 -15
- package/src/channels/discord/attachments.ts +81 -27
- package/src/channels/discord/debounce.ts +25 -0
- package/src/channels/discord/delivery.ts +57 -13
- package/src/channels/discord/human-delay.ts +48 -0
- package/src/channels/discord/inbound.ts +66 -7
- package/src/channels/discord/mentions.ts +42 -18
- package/src/channels/discord/presence.ts +148 -0
- package/src/channels/discord/rate-limiter.ts +58 -0
- package/src/channels/discord/reactions.ts +211 -0
- package/src/channels/discord/runtime.ts +1048 -182
- package/src/channels/discord/stream.ts +73 -27
- package/src/channels/discord/tool-actions.ts +78 -37
- package/src/channels/discord/typing.ts +140 -0
- package/src/chunk.ts +12 -4
- package/src/cli.ts +141 -56
- package/src/config.ts +192 -34
- package/src/container-runner.ts +132 -42
- package/src/container-setup.ts +57 -22
- package/src/conversation.ts +9 -7
- package/src/db.ts +2217 -84
- package/src/delegation-manager.ts +6 -2
- package/src/gateway-client.ts +41 -17
- package/src/gateway-service.ts +1019 -201
- package/src/gateway-types.ts +33 -0
- package/src/gateway.ts +321 -48
- package/src/health.ts +66 -26
- package/src/heartbeat.ts +84 -22
- package/src/hybridai-bots.ts +14 -5
- package/src/instruction-approval-audit.ts +4 -1
- package/src/instruction-integrity.ts +30 -9
- package/src/ipc.ts +23 -5
- package/src/logger.ts +4 -1
- package/src/memory-consolidation.ts +41 -0
- package/src/memory-service.ts +606 -0
- package/src/mount-security.ts +58 -13
- package/src/observability-ingest.ts +134 -35
- package/src/onboarding.ts +126 -35
- package/src/proactive-policy.ts +3 -1
- package/src/prompt-hooks.ts +40 -17
- package/src/runtime-config.ts +1114 -99
- package/src/scheduled-task-runner.ts +63 -11
- package/src/scheduler.ts +683 -60
- package/src/session-export.ts +196 -0
- package/src/session-maintenance.ts +125 -22
- package/src/session-transcripts.ts +12 -3
- package/src/side-effects.ts +28 -5
- package/src/skills-guard.ts +1067 -219
- package/src/skills.ts +163 -65
- package/src/token-efficiency.ts +31 -9
- package/src/tui.ts +166 -25
- package/src/types.ts +195 -2
- package/src/update.ts +79 -23
- package/src/workspace.ts +63 -11
- package/tests/approval-policy.test.ts +224 -0
- package/tests/discord.basic.test.ts +82 -2
- package/tests/discord.human-presence.test.ts +85 -0
- package/tests/gateway-service.media-routing.test.ts +8 -2
- package/tests/memory-service.test.ts +1114 -0
- package/tests/token-efficiency.basic.test.ts +8 -2
- package/vitest.e2e.config.ts +3 -1
- package/vitest.integration.config.ts +3 -1
- package/vitest.live.config.ts +3 -1
- package/vitest.unit.config.ts +9 -0
|
@@ -16,14 +16,22 @@ interface RuntimeEventPayload {
|
|
|
16
16
|
interface RuntimeExtension {
|
|
17
17
|
name: string;
|
|
18
18
|
onEvent?: (payload: RuntimeEventPayload) => void | Promise<void>;
|
|
19
|
-
onBeforeToolCall?: (
|
|
20
|
-
|
|
19
|
+
onBeforeToolCall?: (
|
|
20
|
+
toolName: string,
|
|
21
|
+
args: Record<string, unknown>,
|
|
22
|
+
) => string | null | Promise<string | null>;
|
|
23
|
+
onAfterToolCall?: (
|
|
24
|
+
toolName: string,
|
|
25
|
+
args: Record<string, unknown>,
|
|
26
|
+
result: string,
|
|
27
|
+
) => void | Promise<void>;
|
|
21
28
|
}
|
|
22
29
|
|
|
23
30
|
const DANGEROUS_FILE_CONTENT_PATTERNS: Array<{ re: RegExp; reason: string }> = [
|
|
24
31
|
{
|
|
25
32
|
re: /\brm\s+-rf\s+\/(\s|$)/i,
|
|
26
|
-
reason:
|
|
33
|
+
reason:
|
|
34
|
+
'Detected destructive root delete pattern (`rm -rf /`) in file content.',
|
|
27
35
|
},
|
|
28
36
|
{
|
|
29
37
|
re: /:\(\)\s*\{.*\};\s*:/i,
|
|
@@ -31,7 +39,8 @@ const DANGEROUS_FILE_CONTENT_PATTERNS: Array<{ re: RegExp; reason: string }> = [
|
|
|
31
39
|
},
|
|
32
40
|
{
|
|
33
41
|
re: /\bcurl\b[^\n|]*\|\s*(sh|bash|zsh)\b/i,
|
|
34
|
-
reason:
|
|
42
|
+
reason:
|
|
43
|
+
'Detected remote shell execution pattern (`curl | sh`) in file content.',
|
|
35
44
|
},
|
|
36
45
|
];
|
|
37
46
|
|
|
@@ -50,9 +59,10 @@ const securityHookExtension: RuntimeExtension = {
|
|
|
50
59
|
name: 'security-hook',
|
|
51
60
|
onBeforeToolCall: (toolName, args) => {
|
|
52
61
|
if (toolName === 'write' || toolName === 'edit') {
|
|
53
|
-
const content =
|
|
54
|
-
|
|
55
|
-
|
|
62
|
+
const content =
|
|
63
|
+
toolName === 'write'
|
|
64
|
+
? String(args.contents || '')
|
|
65
|
+
: String(args.new || '');
|
|
56
66
|
for (const pattern of DANGEROUS_FILE_CONTENT_PATTERNS) {
|
|
57
67
|
if (pattern.re.test(content)) return pattern.reason;
|
|
58
68
|
}
|
|
@@ -74,14 +84,17 @@ const runtimeExtensions: RuntimeExtension[] = [securityHookExtension];
|
|
|
74
84
|
function parseArgs(argsJson: string): Record<string, unknown> {
|
|
75
85
|
try {
|
|
76
86
|
const parsed = JSON.parse(argsJson) as unknown;
|
|
77
|
-
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
87
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
88
|
+
return {};
|
|
78
89
|
return parsed as Record<string, unknown>;
|
|
79
90
|
} catch {
|
|
80
91
|
return {};
|
|
81
92
|
}
|
|
82
93
|
}
|
|
83
94
|
|
|
84
|
-
export async function emitRuntimeEvent(
|
|
95
|
+
export async function emitRuntimeEvent(
|
|
96
|
+
payload: RuntimeEventPayload,
|
|
97
|
+
): Promise<void> {
|
|
85
98
|
for (const ext of runtimeExtensions) {
|
|
86
99
|
if (!ext.onEvent) continue;
|
|
87
100
|
try {
|
|
@@ -92,7 +105,10 @@ export async function emitRuntimeEvent(payload: RuntimeEventPayload): Promise<vo
|
|
|
92
105
|
}
|
|
93
106
|
}
|
|
94
107
|
|
|
95
|
-
export async function runBeforeToolHooks(
|
|
108
|
+
export async function runBeforeToolHooks(
|
|
109
|
+
toolName: string,
|
|
110
|
+
argsJson: string,
|
|
111
|
+
): Promise<string | null> {
|
|
96
112
|
const args = parseArgs(argsJson);
|
|
97
113
|
for (const ext of runtimeExtensions) {
|
|
98
114
|
if (!ext.onBeforeToolCall) continue;
|
|
@@ -112,11 +128,19 @@ export async function runBeforeToolHooks(toolName: string, argsJson: string): Pr
|
|
|
112
128
|
// ignore broken extensions
|
|
113
129
|
}
|
|
114
130
|
}
|
|
115
|
-
await emitRuntimeEvent({
|
|
131
|
+
await emitRuntimeEvent({
|
|
132
|
+
event: 'before_tool_call',
|
|
133
|
+
toolName,
|
|
134
|
+
blocked: false,
|
|
135
|
+
});
|
|
116
136
|
return null;
|
|
117
137
|
}
|
|
118
138
|
|
|
119
|
-
export async function runAfterToolHooks(
|
|
139
|
+
export async function runAfterToolHooks(
|
|
140
|
+
toolName: string,
|
|
141
|
+
argsJson: string,
|
|
142
|
+
result: string,
|
|
143
|
+
): Promise<void> {
|
|
120
144
|
const args = parseArgs(argsJson);
|
|
121
145
|
for (const ext of runtimeExtensions) {
|
|
122
146
|
if (!ext.onAfterToolCall) continue;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
ChatCompletionResponse,
|
|
3
|
+
ChatMessage,
|
|
4
|
+
ToolCall,
|
|
5
|
+
ToolDefinition,
|
|
6
|
+
} from './types.js';
|
|
2
7
|
|
|
3
8
|
export class HybridAIRequestError extends Error {
|
|
4
9
|
status: number;
|
|
@@ -86,7 +91,10 @@ function ensureToolCall(toolCalls: ToolCall[], index: number): ToolCall {
|
|
|
86
91
|
return toolCalls[index];
|
|
87
92
|
}
|
|
88
93
|
|
|
89
|
-
function mergeToolCallDelta(
|
|
94
|
+
function mergeToolCallDelta(
|
|
95
|
+
target: ToolCall,
|
|
96
|
+
delta: StreamToolCallDelta,
|
|
97
|
+
): void {
|
|
90
98
|
if (typeof delta.id === 'string' && delta.id) {
|
|
91
99
|
target.id = target.id ? `${target.id}${delta.id}` : delta.id;
|
|
92
100
|
}
|
|
@@ -99,7 +107,10 @@ function mergeToolCallDelta(target: ToolCall, delta: StreamToolCallDelta): void
|
|
|
99
107
|
? `${target.function.name}${delta.function.name}`
|
|
100
108
|
: delta.function.name;
|
|
101
109
|
}
|
|
102
|
-
if (
|
|
110
|
+
if (
|
|
111
|
+
typeof delta.function.arguments === 'string' &&
|
|
112
|
+
delta.function.arguments
|
|
113
|
+
) {
|
|
103
114
|
target.function.arguments += delta.function.arguments;
|
|
104
115
|
}
|
|
105
116
|
}
|
|
@@ -166,11 +177,13 @@ export async function callHybridAIStream(
|
|
|
166
177
|
throw new HybridAIRequestError(response.status, text);
|
|
167
178
|
}
|
|
168
179
|
|
|
169
|
-
const contentType = (
|
|
180
|
+
const contentType = (
|
|
181
|
+
response.headers.get('content-type') || ''
|
|
182
|
+
).toLowerCase();
|
|
170
183
|
if (
|
|
171
|
-
contentType.includes('application/json')
|
|
172
|
-
|
|
173
|
-
|
|
184
|
+
contentType.includes('application/json') &&
|
|
185
|
+
!contentType.includes('ndjson') &&
|
|
186
|
+
!contentType.includes('event-stream')
|
|
174
187
|
) {
|
|
175
188
|
return (await response.json()) as ChatCompletionResponse;
|
|
176
189
|
}
|
|
@@ -208,10 +221,14 @@ export async function callHybridAIStream(
|
|
|
208
221
|
|
|
209
222
|
sawPayload = true;
|
|
210
223
|
if (typeof payload.id === 'string' && payload.id) streamId = payload.id;
|
|
211
|
-
if (typeof payload.model === 'string' && payload.model)
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
224
|
+
if (typeof payload.model === 'string' && payload.model)
|
|
225
|
+
streamModel = payload.model;
|
|
226
|
+
if (payload.usage && typeof payload.usage === 'object')
|
|
227
|
+
usage = payload.usage;
|
|
228
|
+
|
|
229
|
+
const choice = Array.isArray(payload.choices)
|
|
230
|
+
? payload.choices[0]
|
|
231
|
+
: undefined;
|
|
215
232
|
if (!choice) return;
|
|
216
233
|
|
|
217
234
|
if (choice.message) {
|
|
@@ -249,7 +266,10 @@ export async function callHybridAIStream(
|
|
|
249
266
|
}
|
|
250
267
|
if (Array.isArray(delta.tool_calls) && delta.tool_calls.length > 0) {
|
|
251
268
|
for (const callDelta of delta.tool_calls) {
|
|
252
|
-
const index =
|
|
269
|
+
const index =
|
|
270
|
+
typeof callDelta.index === 'number' && callDelta.index >= 0
|
|
271
|
+
? callDelta.index
|
|
272
|
+
: 0;
|
|
253
273
|
const target = ensureToolCall(toolCalls, index);
|
|
254
274
|
mergeToolCallDelta(target, callDelta);
|
|
255
275
|
}
|
|
@@ -293,7 +313,8 @@ export async function callHybridAIStream(
|
|
|
293
313
|
throw new Error('Streaming response ended without payload');
|
|
294
314
|
}
|
|
295
315
|
|
|
296
|
-
const finalFinishReason =
|
|
316
|
+
const finalFinishReason =
|
|
317
|
+
finishReason || (toolCalls.length > 0 ? 'tool_calls' : 'stop');
|
|
297
318
|
return {
|
|
298
319
|
id: streamId || 'stream',
|
|
299
320
|
model: streamModel,
|