@totalreclaw/totalreclaw 3.3.12-rc.2 → 3.3.12-rc.21
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/CHANGELOG.md +26 -0
- package/SKILL.md +34 -249
- package/api-client.ts +17 -9
- package/batch-gate.ts +42 -0
- package/billing-cache.ts +25 -20
- package/claims-helper.ts +7 -1
- package/config.ts +54 -12
- package/consolidation.ts +6 -13
- package/contradiction-sync.ts +19 -14
- package/credential-provider.ts +184 -0
- package/crypto.ts +27 -160
- package/dist/api-client.js +17 -9
- package/dist/batch-gate.js +40 -0
- package/dist/billing-cache.js +19 -21
- package/dist/claims-helper.js +7 -1
- package/dist/config.js +54 -12
- package/dist/consolidation.js +6 -15
- package/dist/contradiction-sync.js +15 -15
- package/dist/credential-provider.js +145 -0
- package/dist/crypto.js +17 -137
- package/dist/download-ux.js +11 -7
- package/dist/embedder-loader.js +266 -0
- package/dist/embedding.js +36 -3
- package/dist/entry.js +123 -0
- package/dist/extractor.js +134 -0
- package/dist/fs-helpers.js +116 -241
- package/dist/import-adapters/chatgpt-adapter.js +14 -0
- package/dist/import-adapters/claude-adapter.js +14 -0
- package/dist/import-adapters/gemini-adapter.js +43 -159
- package/dist/import-adapters/mcp-memory-adapter.js +14 -0
- package/dist/import-state-manager.js +100 -0
- package/dist/index.js +1130 -2520
- package/dist/llm-client.js +69 -1
- package/dist/memory-runtime.js +459 -0
- package/dist/native-memory.js +123 -0
- package/dist/onboarding-cli.js +3 -2
- package/dist/pair-cli.js +1 -1
- package/dist/pair-crypto.js +16 -358
- package/dist/pair-http.js +147 -4
- package/dist/relay.js +140 -0
- package/dist/reranker.js +13 -8
- package/dist/semantic-dedup.js +5 -7
- package/dist/skill-register.js +97 -0
- package/dist/subgraph-search.js +3 -1
- package/dist/subgraph-store.js +315 -282
- package/dist/tool-gating.js +39 -26
- package/dist/tools.js +367 -0
- package/dist/tr-cli-export-helper.js +103 -0
- package/dist/tr-cli.js +220 -127
- package/dist/trajectory-poller.js +155 -9
- package/dist/vault-crypto.js +551 -0
- package/download-ux.ts +12 -6
- package/embedder-loader.ts +293 -1
- package/embedding.ts +43 -3
- package/entry.ts +132 -0
- package/extractor.ts +167 -0
- package/fs-helpers.ts +166 -292
- package/import-adapters/chatgpt-adapter.ts +18 -0
- package/import-adapters/claude-adapter.ts +18 -0
- package/import-adapters/gemini-adapter.ts +56 -183
- package/import-adapters/mcp-memory-adapter.ts +18 -0
- package/import-adapters/types.ts +1 -1
- package/import-state-manager.ts +139 -0
- package/index.ts +1432 -3002
- package/llm-client.ts +74 -1
- package/memory-runtime.ts +723 -0
- package/native-memory.ts +196 -0
- package/onboarding-cli.ts +3 -2
- package/openclaw.plugin.json +5 -17
- package/package.json +7 -4
- package/pair-cli.ts +1 -1
- package/pair-crypto.ts +41 -483
- package/pair-http.ts +194 -5
- package/postinstall.mjs +138 -0
- package/relay.ts +172 -0
- package/reranker.ts +13 -8
- package/semantic-dedup.ts +5 -6
- package/skill-register.ts +146 -0
- package/skill.json +1 -1
- package/subgraph-search.ts +3 -1
- package/subgraph-store.ts +334 -299
- package/tool-gating.ts +39 -26
- package/tools.ts +499 -0
- package/tr-cli-export-helper.ts +138 -0
- package/tr-cli.ts +263 -133
- package/trajectory-poller.ts +162 -10
- package/vault-crypto.ts +705 -0
package/llm-client.ts
CHANGED
|
@@ -801,6 +801,48 @@ export function isRetryable(errorMessage: string): boolean {
|
|
|
801
801
|
// OpenAI-compatible chat completion
|
|
802
802
|
// ---------------------------------------------------------------------------
|
|
803
803
|
|
|
804
|
+
/**
|
|
805
|
+
* Provider base-URL hints for OpenAI-compatible endpoints that honour the
|
|
806
|
+
* `response_format: {"type": "json_object"}` body field. Sending the field
|
|
807
|
+
* to a provider that supports it makes JSON output deterministic; sending
|
|
808
|
+
* it to a provider that does NOT recognise the field is a 400.
|
|
809
|
+
*
|
|
810
|
+
* Why this exists (3.3.12-rc.6, 2026-05-09):
|
|
811
|
+
* z.ai's GLM family (4.5-flash, 5-turbo, 5.1) silently returns EMPTY
|
|
812
|
+
* `message.content` for the merged-extraction prompt unless this hint
|
|
813
|
+
* is set. No error, no warning — the LLM just emits "" instead of the
|
|
814
|
+
* expected `{"topics": [], "facts": []}` JSON. Plugin's parse step
|
|
815
|
+
* then logs `0 raw facts` from a successful-but-empty branch.
|
|
816
|
+
*
|
|
817
|
+
* This bug was found and fixed on the Python (Hermes) side in
|
|
818
|
+
* 2.3.1-rc.23 (see `python/src/totalreclaw/agent/llm_client.py`
|
|
819
|
+
* `_supports_json_object_response_format`) but the plugin TS port did
|
|
820
|
+
* not carry the fix — observed in plugin 3.3.12-rc.5 auto-QA on
|
|
821
|
+
* 2026-05-09: hook + poller both fired correctly but extraction
|
|
822
|
+
* returned 0 facts on every batch despite trajectories containing
|
|
823
|
+
* explicit "I prefer X" / "I work at Y" statements.
|
|
824
|
+
*
|
|
825
|
+
* Mirror of Python's `_supports_json_object_response_format`. Match by
|
|
826
|
+
* substring on a lowercased baseUrl so cosmetic prefix differences
|
|
827
|
+
* (https://, /v1, etc.) don't matter.
|
|
828
|
+
*/
|
|
829
|
+
const JSON_OBJECT_PROVIDER_HINTS = [
|
|
830
|
+
'z.ai',
|
|
831
|
+
'api.openai.com',
|
|
832
|
+
'groq.com',
|
|
833
|
+
'openrouter.ai',
|
|
834
|
+
'deepseek.com',
|
|
835
|
+
'mistral.ai',
|
|
836
|
+
'x.ai',
|
|
837
|
+
'together.xyz',
|
|
838
|
+
] as const;
|
|
839
|
+
|
|
840
|
+
export function supportsJsonObjectResponseFormat(baseUrl: string | undefined): boolean {
|
|
841
|
+
if (!baseUrl) return false;
|
|
842
|
+
const lower = baseUrl.toLowerCase();
|
|
843
|
+
return JSON_OBJECT_PROVIDER_HINTS.some((h) => lower.includes(h));
|
|
844
|
+
}
|
|
845
|
+
|
|
804
846
|
async function chatCompletionOpenAI(
|
|
805
847
|
config: LLMClientConfig,
|
|
806
848
|
messages: ChatMessage[],
|
|
@@ -817,6 +859,13 @@ async function chatCompletionOpenAI(
|
|
|
817
859
|
max_completion_tokens: maxTokens,
|
|
818
860
|
};
|
|
819
861
|
|
|
862
|
+
// 3.3.12-rc.6: hint the provider to return strict JSON. Critical for
|
|
863
|
+
// z.ai/GLM (silent-empty without it). See JSON_OBJECT_PROVIDER_HINTS
|
|
864
|
+
// doc above.
|
|
865
|
+
if (supportsJsonObjectResponseFormat(config.baseUrl)) {
|
|
866
|
+
body.response_format = { type: 'json_object' };
|
|
867
|
+
}
|
|
868
|
+
|
|
820
869
|
try {
|
|
821
870
|
const res = await fetch(url, {
|
|
822
871
|
method: 'POST',
|
|
@@ -834,7 +883,31 @@ async function chatCompletionOpenAI(
|
|
|
834
883
|
}
|
|
835
884
|
|
|
836
885
|
const json = (await res.json()) as ChatCompletionResponse;
|
|
837
|
-
|
|
886
|
+
const content = json.choices?.[0]?.message?.content ?? null;
|
|
887
|
+
|
|
888
|
+
// 3.3.12-rc.6: loud-on-empty. If the provider returned a 200 with
|
|
889
|
+
// empty content, this almost always means a missing response_format
|
|
890
|
+
// hint or a content-filter. Without this log the silent-empty
|
|
891
|
+
// failure mode (Python rc.23 / plugin rc.5) is invisible to ops.
|
|
892
|
+
if (content === '' || content === null) {
|
|
893
|
+
// Lazy import to avoid circular dep with the registered logger.
|
|
894
|
+
// Fall back to console.warn if logger unavailable.
|
|
895
|
+
const warn = (msg: string) => {
|
|
896
|
+
try {
|
|
897
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
898
|
+
(globalThis as any)?.console?.warn?.(msg);
|
|
899
|
+
} catch {
|
|
900
|
+
/* noop */
|
|
901
|
+
}
|
|
902
|
+
};
|
|
903
|
+
warn(
|
|
904
|
+
`[totalreclaw][llm-client] provider=${config.baseUrl} model=${config.model} ` +
|
|
905
|
+
`returned empty content (status=200). ` +
|
|
906
|
+
`If using z.ai/GLM/OpenAI-compat, check response_format hint is being sent.`,
|
|
907
|
+
);
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
return content;
|
|
838
911
|
} catch (err) {
|
|
839
912
|
const msg = err instanceof Error ? err.message : String(err);
|
|
840
913
|
throw new Error(`LLM call failed: ${msg}`);
|