@hybridaione/hybridclaw 0.2.7 → 0.2.10

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 (181) hide show
  1. package/CHANGELOG.md +63 -1
  2. package/README.md +5 -9
  3. package/config.example.json +2 -0
  4. package/container/package-lock.json +2 -2
  5. package/container/package.json +11 -2
  6. package/container/src/index.ts +22 -21
  7. package/container/src/model-retry.ts +19 -0
  8. package/container/src/tools.ts +445 -38
  9. package/container/src/types.ts +1 -0
  10. package/dist/channels/discord/prompt-adapter.d.ts +3 -0
  11. package/dist/channels/discord/prompt-adapter.d.ts.map +1 -0
  12. package/dist/channels/discord/prompt-adapter.js +26 -0
  13. package/dist/channels/discord/prompt-adapter.js.map +1 -0
  14. package/dist/channels/discord/runtime.d.ts.map +1 -1
  15. package/dist/channels/discord/runtime.js +41 -6
  16. package/dist/channels/discord/runtime.js.map +1 -1
  17. package/dist/channels/discord/send-permissions.d.ts +19 -0
  18. package/dist/channels/discord/send-permissions.d.ts.map +1 -0
  19. package/dist/channels/discord/send-permissions.js +112 -0
  20. package/dist/channels/discord/send-permissions.js.map +1 -0
  21. package/dist/channels/discord/tool-actions.d.ts +13 -1
  22. package/dist/channels/discord/tool-actions.d.ts.map +1 -1
  23. package/dist/channels/discord/tool-actions.js +778 -17
  24. package/dist/channels/discord/tool-actions.js.map +1 -1
  25. package/dist/channels/prompt-adapters.d.ts +14 -0
  26. package/dist/channels/prompt-adapters.d.ts.map +1 -0
  27. package/dist/channels/prompt-adapters.js +37 -0
  28. package/dist/channels/prompt-adapters.js.map +1 -0
  29. package/dist/config.d.ts +2 -0
  30. package/dist/config.d.ts.map +1 -1
  31. package/dist/config.js +4 -0
  32. package/dist/config.js.map +1 -1
  33. package/dist/container-runner.d.ts.map +1 -1
  34. package/dist/container-runner.js +31 -7
  35. package/dist/container-runner.js.map +1 -1
  36. package/dist/gateway-service.d.ts.map +1 -1
  37. package/dist/gateway-service.js +12 -3
  38. package/dist/gateway-service.js.map +1 -1
  39. package/dist/gateway.js +43 -8
  40. package/dist/gateway.js.map +1 -1
  41. package/dist/health.d.ts.map +1 -1
  42. package/dist/health.js +69 -12
  43. package/dist/health.js.map +1 -1
  44. package/dist/hybridai-models.d.ts.map +1 -1
  45. package/dist/hybridai-models.js +42 -4
  46. package/dist/hybridai-models.js.map +1 -1
  47. package/dist/prompt-hooks.d.ts +3 -0
  48. package/dist/prompt-hooks.d.ts.map +1 -1
  49. package/dist/prompt-hooks.js +40 -4
  50. package/dist/prompt-hooks.js.map +1 -1
  51. package/dist/runtime-config.d.ts +8 -0
  52. package/dist/runtime-config.d.ts.map +1 -1
  53. package/dist/runtime-config.js +35 -1
  54. package/dist/runtime-config.js.map +1 -1
  55. package/dist/silent-reply-stream.d.ts +6 -0
  56. package/dist/silent-reply-stream.d.ts.map +1 -0
  57. package/dist/silent-reply-stream.js +51 -0
  58. package/dist/silent-reply-stream.js.map +1 -0
  59. package/dist/silent-reply.d.ts +5 -0
  60. package/dist/silent-reply.d.ts.map +1 -0
  61. package/dist/silent-reply.js +31 -0
  62. package/dist/silent-reply.js.map +1 -0
  63. package/dist/types.d.ts +1 -0
  64. package/dist/types.d.ts.map +1 -1
  65. package/dist/types.js.map +1 -1
  66. package/docs/index.html +10 -10
  67. package/package.json +26 -3
  68. package/.github/workflows/ci.yml +0 -70
  69. package/.github/workflows/pages.yml +0 -41
  70. package/.husky/pre-commit +0 -1
  71. package/CONTRIBUTING.md +0 -33
  72. package/biome.json +0 -35
  73. package/dist/colors.d.ts +0 -18
  74. package/dist/colors.d.ts.map +0 -1
  75. package/dist/colors.js +0 -27
  76. package/dist/colors.js.map +0 -1
  77. package/dist/discord-stream.d.ts +0 -32
  78. package/dist/discord-stream.d.ts.map +0 -1
  79. package/dist/discord-stream.js +0 -196
  80. package/dist/discord-stream.js.map +0 -1
  81. package/dist/discord.basic.test.d.ts +0 -2
  82. package/dist/discord.basic.test.d.ts.map +0 -1
  83. package/dist/discord.basic.test.js +0 -38
  84. package/dist/discord.basic.test.js.map +0 -1
  85. package/dist/discord.d.ts +0 -6
  86. package/dist/discord.d.ts.map +0 -1
  87. package/dist/discord.js +0 -4
  88. package/dist/discord.js.map +0 -1
  89. package/dist/gateway-service.media-routing.test.d.ts +0 -2
  90. package/dist/gateway-service.media-routing.test.d.ts.map +0 -1
  91. package/dist/gateway-service.media-routing.test.js +0 -29
  92. package/dist/gateway-service.media-routing.test.js.map +0 -1
  93. package/dist/git-commit.d.ts +0 -2
  94. package/dist/git-commit.d.ts.map +0 -1
  95. package/dist/git-commit.js +0 -63
  96. package/dist/git-commit.js.map +0 -1
  97. package/dist/hatch.d.ts +0 -7
  98. package/dist/hatch.d.ts.map +0 -1
  99. package/dist/hatch.js +0 -99
  100. package/dist/hatch.js.map +0 -1
  101. package/dist/index.d.ts +0 -2
  102. package/dist/index.d.ts.map +0 -1
  103. package/dist/index.js +0 -60
  104. package/dist/index.js.map +0 -1
  105. package/dist/token-efficiency.basic.test.d.ts +0 -2
  106. package/dist/token-efficiency.basic.test.d.ts.map +0 -1
  107. package/dist/token-efficiency.basic.test.js +0 -29
  108. package/dist/token-efficiency.basic.test.js.map +0 -1
  109. package/src/agent.ts +0 -86
  110. package/src/audit-cli.ts +0 -327
  111. package/src/audit-events.ts +0 -201
  112. package/src/audit-trail.ts +0 -428
  113. package/src/channels/discord/attachments.ts +0 -336
  114. package/src/channels/discord/debounce.ts +0 -25
  115. package/src/channels/discord/delivery.ts +0 -150
  116. package/src/channels/discord/human-delay.ts +0 -48
  117. package/src/channels/discord/inbound.ts +0 -260
  118. package/src/channels/discord/mentions.ts +0 -154
  119. package/src/channels/discord/presence.ts +0 -148
  120. package/src/channels/discord/rate-limiter.ts +0 -58
  121. package/src/channels/discord/reactions.ts +0 -211
  122. package/src/channels/discord/runtime.ts +0 -2216
  123. package/src/channels/discord/stream.ts +0 -294
  124. package/src/channels/discord/tool-actions.ts +0 -373
  125. package/src/channels/discord/typing.ts +0 -140
  126. package/src/chunk.ts +0 -161
  127. package/src/cli.ts +0 -911
  128. package/src/config.ts +0 -403
  129. package/src/container-runner.ts +0 -522
  130. package/src/container-setup.ts +0 -317
  131. package/src/conversation.ts +0 -82
  132. package/src/db.ts +0 -2718
  133. package/src/delegation-manager.ts +0 -49
  134. package/src/env.ts +0 -36
  135. package/src/gateway-client.ts +0 -241
  136. package/src/gateway-service.ts +0 -2708
  137. package/src/gateway-types.ts +0 -137
  138. package/src/gateway.ts +0 -827
  139. package/src/health.ts +0 -357
  140. package/src/heartbeat.ts +0 -419
  141. package/src/hybridai-bots.ts +0 -57
  142. package/src/hybridai-models.ts +0 -158
  143. package/src/instruction-approval-audit.ts +0 -90
  144. package/src/instruction-integrity.ts +0 -197
  145. package/src/ipc.ts +0 -181
  146. package/src/logger.ts +0 -29
  147. package/src/memory-consolidation.ts +0 -41
  148. package/src/memory-service.ts +0 -606
  149. package/src/mount-security.ts +0 -261
  150. package/src/observability-ingest.ts +0 -888
  151. package/src/onboarding.ts +0 -719
  152. package/src/proactive-policy.ts +0 -46
  153. package/src/prompt-hooks.ts +0 -326
  154. package/src/runtime-config.ts +0 -1808
  155. package/src/scheduled-task-runner.ts +0 -256
  156. package/src/scheduler.ts +0 -819
  157. package/src/session-export.ts +0 -196
  158. package/src/session-maintenance.ts +0 -367
  159. package/src/session-transcripts.ts +0 -54
  160. package/src/side-effects.ts +0 -97
  161. package/src/skills-guard.ts +0 -1584
  162. package/src/skills.ts +0 -1036
  163. package/src/token-efficiency.ts +0 -266
  164. package/src/tui.ts +0 -604
  165. package/src/types.ts +0 -428
  166. package/src/update.ts +0 -445
  167. package/src/workspace.ts +0 -223
  168. package/tests/approval-policy.test.ts +0 -335
  169. package/tests/discord.basic.test.ts +0 -304
  170. package/tests/discord.human-presence.test.ts +0 -85
  171. package/tests/gateway-service.media-routing.test.ts +0 -39
  172. package/tests/hybridai-client.test.ts +0 -112
  173. package/tests/hybridai-models.test.ts +0 -46
  174. package/tests/memory-service.test.ts +0 -1114
  175. package/tests/token-efficiency.basic.test.ts +0 -38
  176. package/tests/token-usage.cache.test.ts +0 -128
  177. package/tsconfig.json +0 -18
  178. package/vitest.e2e.config.ts +0 -17
  179. package/vitest.integration.config.ts +0 -17
  180. package/vitest.live.config.ts +0 -18
  181. package/vitest.unit.config.ts +0 -24
package/CHANGELOG.md CHANGED
@@ -2,7 +2,69 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
- No unreleased changes.
5
+ ### Added
6
+
7
+ ### Changed
8
+
9
+ ### Fixed
10
+
11
+ ## [0.2.10](https://github.com/HybridAIOne/hybridclaw/tree/v0.2.10)
12
+
13
+ ### Added
14
+
15
+ - **Model retry policy helpers + tests**: Added shared model stream-fallback/retry predicates with dedicated unit coverage for retryable/non-retryable HybridAI error classes.
16
+ - **Message tool schema regression test**: Added explicit schema test coverage to enforce valid `components` parameter structure for the `message` tool definition.
17
+
18
+ ### Changed
19
+
20
+ - **Stream failure fallback behavior**: Container model-call flow now applies stream-to-non-stream fallback policy through centralized retry helpers for consistent error classification.
21
+
22
+ ### Fixed
23
+
24
+ - **HybridAI function schema rejection**: Fixed `message` tool `components` schema by defining `items` for the array variant, resolving `invalid_function_parameters` 400 failures.
25
+ - **HybridAI 500 handling robustness**: Streamed 5xx API failures now trigger the non-stream fallback path before hard-failing the turn.
26
+
27
+ ## [0.2.9](https://github.com/HybridAIOne/hybridclaw/tree/v0.2.9)
28
+
29
+ ### Added
30
+
31
+ - **Release bundle guard scripts**: Added root and container `release:check` scripts that validate `npm pack --dry-run` contents and fail on forbidden files (tests, source, CI/config artifacts).
32
+ - **Dry-run publish helpers**: Added `publish:dry` scripts for root and container package smoke checks before publish.
33
+
34
+ ### Changed
35
+
36
+ - **NPM package allowlists**: Added explicit `files` allowlists for root and container packages so publish output is limited to runtime assets and docs/templates/skills that HybridClaw loads at runtime.
37
+ - **Prepack gating**: Root and container packages now run clean build + release bundle validation during `prepack`.
38
+ - **CI packaging checks**: CI now runs root/container release bundle checks to catch publish-regression changes on PRs and pushes.
39
+ - **Silent reply token handling**: Centralized `__MESSAGE_SEND_HANDLED__` parsing/cleanup, added streaming prefix buffering for Discord/API output paths, and aligned prompt token constants with shared silent-reply utilities.
40
+ - **CLI build output mode**: Root `build` script now enforces executable mode on `dist/cli.js` after TypeScript compilation.
41
+
42
+ ### Fixed
43
+
44
+ - **Silent token leakage in streams/history**: Streaming token fragments are now suppressed until divergence/confirmation, trailing silent tokens are stripped from mixed replies, and silent assistant placeholders are filtered from conversation history before model calls.
45
+
46
+ ## [0.2.8](https://github.com/HybridAIOne/hybridclaw/tree/v0.2.8)
47
+
48
+ ### Added
49
+
50
+ - **Discord send policy controls**: Added runtime config for `discord.sendPolicy` (`open|allowlist|disabled`) with global/channel/guild/user/role allowlist checks for outbound sends.
51
+ - **Channel-aware prompt adapters**: Added channel-specific message-tool hint adapters (including Discord action/component guidance) injected into system prompts.
52
+ - **Expanded Discord message actions**: Added `react`, `quote-reply`, `edit`, `delete`, `pin`, `unpin`, `thread-create`, and `thread-reply` actions to the `message` tool path.
53
+ - **Message-tool regression coverage**: Added focused unit coverage for action aliases, target normalization, member/channel lookup behavior, send-policy checks, and channel hint injection.
54
+
55
+ ### Changed
56
+
57
+ - **Message-tool intent guidance**: System prompt guidance now includes explicit send/post/DM/notify triggers, send parameter guidance (`to` + message), and reply suppression token handling for tool-only sends.
58
+ - **Action alias + target normalization**: Message action normalization now supports natural aliases (`dm`, `post`, `reply`, `respond`, `history`, `fetch`, `lookup`, `whois`) and normalizes Discord prefixes/mentions.
59
+ - **Tool description enrichment**: `message` tool descriptions now emphasize natural-language intent phrases and enumerate current/other configured Discord channels with supported actions.
60
+ - **Single-call DM targeting**: `send` now resolves user targets inline (IDs, mentions, usernames/display names with guild context), including fallback via `user`/`username` when no explicit channel target is passed.
61
+ - **Discord action API flexibility**: `/api/discord/action` now accepts normalized aliases and extended send payload fields (`components`, `contextChannelId`, threading/message mutation fields).
62
+
63
+ ### Fixed
64
+
65
+ - **Structured target-resolution errors**: Member/user lookup failures now return structured JSON errors with disambiguation candidates and actionable hints.
66
+ - **Ambiguous target handling**: Added `resolveAmbiguous` support (`error|best`) to allow safe candidate return or best-match auto-resolution for member/user lookups.
67
+ - **Duplicate send-reply leakage**: Gateway chat responses now strip the message-send silent reply token and normalize final user-visible success text.
6
68
 
7
69
  ## [0.2.7](https://github.com/HybridAIOne/hybridclaw/tree/v0.2.7)
8
70
 
package/README.md CHANGED
@@ -11,17 +11,13 @@ npm install -g @hybridaione/hybridclaw
11
11
  hybridclaw onboarding
12
12
  ```
13
13
 
14
- Latest release: [v0.2.7](https://github.com/HybridAIOne/hybridclaw/releases/tag/v0.2.7)
14
+ Latest release: [v0.2.10](https://github.com/HybridAIOne/hybridclaw/releases/tag/v0.2.10)
15
15
 
16
- ## Release highlights (v0.2.7)
16
+ ## Release highlights (v0.2.10)
17
17
 
18
- - Private approval flow via `/approve [view|yes|session|agent|no] [approval_id]` with ephemeral responses, and DM-ready global slash registration for `/status` + `/approve`.
19
- - Discord command access controls now support `discord.commandMode` (`public|restricted`) plus `discord.commandAllowedUserIds` (with legacy `commandUserId` compatibility).
20
- - Free-mode Discord replies now apply stronger relevance gating (for example short acknowledgements/URL-only chatter are skipped, and messages mentioning other users are de-prioritized).
21
- - `browser_upload` now supports selector targets and automatic fallback from wrapper refs to detected `input[type="file"]` elements.
22
- - HybridAI status/usage context metrics now use a curated static context-window catalog (Claude/Gemini/GPT-5) with family-aware fallback matching, and runtime supports `hybridai.maxTokens` for default completion budgeting.
23
- - Model-usage telemetry now captures cache read/write token counters where providers expose them, and prompt-dump diagnostics include media plus allowed/blocked tool context.
24
- - CLI container readiness checks now resolve the package install root to avoid non-root invocation failures.
18
+ - Fixed HybridAI `400 invalid_function_parameters` failures by correcting `message.components` schema (`array` now defines `items`).
19
+ - Improved HybridAI reliability by centralizing stream-fallback/retry error classification in the container runtime.
20
+ - Added regression tests for message-tool schema validity and HybridAI retry/fallback behavior.
25
21
 
26
22
  ## HybridAI Advantage
27
23
 
@@ -19,6 +19,8 @@
19
19
  "commandAllowedUserIds": [],
20
20
  "commandUserId": "",
21
21
  "groupPolicy": "open",
22
+ "sendPolicy": "open",
23
+ "sendAllowedChannelIds": [],
22
24
  "freeResponseChannels": [],
23
25
  "textChunkLimit": 2000,
24
26
  "maxLinesPerMessage": 17,
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "hybridclaw-agent",
3
- "version": "0.2.7",
3
+ "version": "0.2.10",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "hybridclaw-agent",
9
- "version": "0.2.7",
9
+ "version": "0.2.10",
10
10
  "dependencies": {
11
11
  "@mozilla/readability": "^0.6.0",
12
12
  "agent-browser": "^0.15.1",
@@ -1,10 +1,19 @@
1
1
  {
2
2
  "name": "hybridclaw-agent",
3
- "version": "0.2.7",
3
+ "version": "0.2.10",
4
4
  "type": "module",
5
+ "main": "dist/index.js",
6
+ "files": [
7
+ "dist/",
8
+ "Dockerfile"
9
+ ],
5
10
  "scripts": {
11
+ "clean": "node -e \"const fs=require('node:fs');fs.rmSync('dist',{recursive:true,force:true});\"",
6
12
  "build": "tsc",
7
- "lint": "tsc --noEmit --noUnusedLocals --noUnusedParameters"
13
+ "lint": "tsc --noEmit --noUnusedLocals --noUnusedParameters",
14
+ "prepack": "npm run clean && npm run build && npm run release:check",
15
+ "release:check": "node ./scripts/release-check.mjs",
16
+ "publish:dry": "npm publish --dry-run"
8
17
  },
9
18
  "dependencies": {
10
19
  "@mozilla/readability": "^0.6.0",
@@ -8,12 +8,12 @@ import {
8
8
  runAfterToolHooks,
9
9
  runBeforeToolHooks,
10
10
  } from './extensions.js';
11
- import {
12
- callHybridAI,
13
- callHybridAIStream,
14
- HybridAIRequestError,
15
- } from './hybridai-client.js';
11
+ import { callHybridAI, callHybridAIStream } from './hybridai-client.js';
16
12
  import { waitForInput, writeOutput } from './ipc.js';
13
+ import {
14
+ isRetryableModelError,
15
+ shouldFallbackFromStreamError,
16
+ } from './model-retry.js';
17
17
  import {
18
18
  accumulateApiUsage,
19
19
  createTokenUsageStats,
@@ -23,6 +23,7 @@ import {
23
23
  } from './token-usage.js';
24
24
  import {
25
25
  executeTool,
26
+ getMessageToolDescription,
26
27
  getPendingSideEffects,
27
28
  resetSideEffects,
28
29
  setGatewayContext,
@@ -304,16 +305,6 @@ function emitStreamDelta(delta: string): void {
304
305
  console.error(`[stream] ${payload}`);
305
306
  }
306
307
 
307
- function isRetryableError(err: unknown): boolean {
308
- if (err instanceof HybridAIRequestError) {
309
- return err.status === 429 || (err.status >= 500 && err.status <= 504);
310
- }
311
- const message = err instanceof Error ? err.message : String(err);
312
- return /fetch failed|network|socket|timeout|timed out|ECONNRESET|ECONNREFUSED|EAI_AGAIN/i.test(
313
- message,
314
- );
315
- }
316
-
317
308
  function inferToolError(result: string, blockedReason: string | null): boolean {
318
309
  if (blockedReason) return true;
319
310
  return /\b(error|failed|denied|forbidden|timed out|timeout|exception|invalid)\b/i.test(
@@ -537,11 +528,7 @@ async function callHybridAIWithRetry(params: {
537
528
  maxTokens,
538
529
  );
539
530
  } catch (streamErr) {
540
- const fallbackEligible =
541
- streamErr instanceof HybridAIRequestError &&
542
- streamErr.status >= 400 &&
543
- streamErr.status < 500 &&
544
- streamErr.status !== 429;
531
+ const fallbackEligible = shouldFallbackFromStreamError(streamErr);
545
532
  if (!fallbackEligible) throw streamErr;
546
533
  response = await callHybridAI(
547
534
  baseUrl,
@@ -574,7 +561,9 @@ async function callHybridAIWithRetry(params: {
574
561
  return response;
575
562
  } catch (err) {
576
563
  const retryable =
577
- RETRY_ENABLED && isRetryableError(err) && attempt < RETRY_MAX_ATTEMPTS;
564
+ RETRY_ENABLED &&
565
+ isRetryableModelError(err) &&
566
+ attempt < RETRY_MAX_ATTEMPTS;
578
567
  await emitRuntimeEvent({
579
568
  event: retryable ? 'model_retry' : 'model_error',
580
569
  attempt,
@@ -940,6 +929,16 @@ function resolveTools(input: ContainerInput): ToolDefinition[] {
940
929
  );
941
930
  tools = tools.filter((tool) => !blocked.has(tool.function.name));
942
931
  }
932
+ tools = tools.map((tool) => {
933
+ if (tool.function.name !== 'message') return tool;
934
+ return {
935
+ ...tool,
936
+ function: {
937
+ ...tool.function,
938
+ description: getMessageToolDescription(input.channelId),
939
+ },
940
+ };
941
+ });
943
942
  // Sort alphabetically for deterministic tool ordering (request/cache stability)
944
943
  tools.sort((a, b) => a.function.name.localeCompare(b.function.name));
945
944
  return tools;
@@ -979,6 +978,7 @@ async function main(): Promise<void> {
979
978
  firstInput.gatewayBaseUrl,
980
979
  firstInput.gatewayApiToken,
981
980
  firstInput.channelId,
981
+ firstInput.configuredDiscordChannels,
982
982
  );
983
983
  setModelContext(
984
984
  firstInput.baseUrl,
@@ -1074,6 +1074,7 @@ async function main(): Promise<void> {
1074
1074
  input.gatewayBaseUrl,
1075
1075
  input.gatewayApiToken,
1076
1076
  input.channelId,
1077
+ input.configuredDiscordChannels,
1077
1078
  );
1078
1079
  setModelContext(input.baseUrl, apiKey, input.model, input.chatbotId);
1079
1080
  setMediaContext(input.media);
@@ -0,0 +1,19 @@
1
+ import { HybridAIRequestError } from './hybridai-client.js';
2
+
3
+ const TRANSIENT_NETWORK_ERROR_RE =
4
+ /fetch failed|network|socket|timeout|timed out|ECONNRESET|ECONNREFUSED|EAI_AGAIN/i;
5
+
6
+ export function shouldFallbackFromStreamError(error: unknown): boolean {
7
+ if (!(error instanceof HybridAIRequestError)) return false;
8
+ // Keep 429 on retry/backoff path; fallback does not help throttling.
9
+ if (error.status === 429) return false;
10
+ return error.status >= 400 && error.status <= 599;
11
+ }
12
+
13
+ export function isRetryableModelError(error: unknown): boolean {
14
+ if (error instanceof HybridAIRequestError) {
15
+ return error.status === 429 || (error.status >= 500 && error.status <= 504);
16
+ }
17
+ const message = error instanceof Error ? error.message : String(error);
18
+ return TRANSIENT_NETWORK_ERROR_RE.test(message);
19
+ }