@@ -28,6 +28,21 @@ function cfg(mode: "tools" | "off", patterns?: string[]): OpenClawConfig {
2828 } satisfies OpenClawConfig ;
2929}
3030
31+ function googleCompatCfg ( ) : OpenClawConfig {
32+ return {
33+ ...cfg ( "tools" ) ,
34+ models : {
35+ providers : {
36+ "google-compatible-proxy" : {
37+ api : "openai-completions" ,
38+ baseUrl : "https://generativelanguage.googleapis.com/v1beta/openai" ,
39+ models : [ ] ,
40+ } ,
41+ } ,
42+ } ,
43+ } satisfies OpenClawConfig ;
44+ }
45+
3146const EMAIL_PATTERN = String . raw `([\w]|[-.])+@([\w]|[-.])+\.\w+` ;
3247const IMAGE_BASE64_WITH_SECRET_TOKEN_SUBSTRING =
3348 "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+/p9sAAAARcnVOZAAAAKIDABCDEFGHIJKLMNOP8JJRuAAAAABJRU5ErkJggg==" ;
@@ -39,6 +54,10 @@ const CIPHERTEXT_WITH_TOKEN_SHAPED_BYTES =
3954 "gAAAAABpQnQrXzzZqcAfo3unbAY-ku84xgsvB0fpLkbDvSh3WS5qzfSCmcgwr8_abcdefghijvK2RyV2GQ4ohzcfYwhRwTvY76TvR7Tvr_" ;
4055const GOOGLE_THOUGHT_SIGNATURE = Buffer . from ( `thought-${ "x" . repeat ( 32 ) } ` ) . toString ( "base64" ) ;
4156const SHORT_GOOGLE_THOUGHT_SIGNATURE = "c2ln" ;
57+ const GOOGLE_CREDENTIAL_COLLISION = `AAAAAIza${ "A" . repeat ( 20 ) } ` ;
58+ const ALIBABA_CREDENTIAL_COLLISION = `AAAALTAI${ "B" . repeat ( 12 ) } ` ;
59+ const OPAQUE_CREDENTIAL_COLLISION = `signature.v2:${ GOOGLE_CREDENTIAL_COLLISION } ` ;
60+ const OPENAI_COMPAT_OPAQUE_COLLISION = `SIG-${ GOOGLE_CREDENTIAL_COLLISION } ` ;
4261const COPILOT_CONNECTION_BOUND_ID = Buffer . from ( `message-${ "y" . repeat ( 24 ) } ` ) . toString ( "base64" ) ;
4362const OPENAI_REASONING_REPLAY_METADATA = {
4463 v : 1 ,
@@ -317,7 +336,7 @@ describe("redactTranscriptMessage", () => {
317336 type : "toolCall" ,
318337 id : "call_1" ,
319338 name : "send_request" ,
320- thoughtSignature : CIPHERTEXT_WITH_TOKEN_SHAPED_BYTES ,
339+ thoughtSignature : GOOGLE_THOUGHT_SIGNATURE ,
321340 arguments : {
322341 apiKey : "plainsecretvalue123" ,
323342 thinkingSignature : "sk-abcdef1234567890xyz" ,
@@ -345,7 +364,7 @@ describe("redactTranscriptMessage", () => {
345364 arguments : Record < string , string > ;
346365 } >
347366 ) [ 0 ] ;
348- expect ( block . thoughtSignature ) . toBe ( CIPHERTEXT_WITH_TOKEN_SHAPED_BYTES ) ;
367+ expect ( block . thoughtSignature ) . toBe ( GOOGLE_THOUGHT_SIGNATURE ) ;
349368 expect ( JSON . stringify ( block . arguments ) ) . not . toContain ( "sk-abcdef1234567890xyz" ) ;
350369 expect ( block . arguments . apiKey ) . toBe ( "plains…e123" ) ;
351370 } ) ;
@@ -369,7 +388,7 @@ describe("redactTranscriptMessage", () => {
369388 {
370389 type : "thinking" ,
371390 thinking : "secret sk-abcdef1234567890xyz" ,
372- thought_signature : CIPHERTEXT_WITH_TOKEN_SHAPED_BYTES ,
391+ thought_signature : SHORT_GOOGLE_THOUGHT_SIGNATURE ,
373392 } ,
374393 ] ,
375394 } as unknown as AgentMessage ;
@@ -380,7 +399,7 @@ describe("redactTranscriptMessage", () => {
380399 expect ( blocks [ 0 ] . textSignature ) . toBe ( GOOGLE_THOUGHT_SIGNATURE ) ;
381400 expect ( blocks [ 1 ] . textSignature ) . not . toContain ( "sk-abcdef1234567890xyz" ) ;
382401 expect ( blocks [ 2 ] . thinking ) . not . toContain ( "sk-abcdef1234567890xyz" ) ;
383- expect ( blocks [ 2 ] . thought_signature ) . toBe ( CIPHERTEXT_WITH_TOKEN_SHAPED_BYTES ) ;
402+ expect ( blocks [ 2 ] . thought_signature ) . toBe ( SHORT_GOOGLE_THOUGHT_SIGNATURE ) ;
384403 } ) ;
385404
386405 it . each ( [ "openai-responses" , "openclaw-openai-responses-transport" ] ) (
@@ -444,14 +463,13 @@ describe("redactTranscriptMessage", () => {
444463 expect ( redactedBlock . metadata . accessToken ) . toBe ( "nested…t123" ) ;
445464 } ) ;
446465
447- it ( "redacts credential-shaped values even on provider signature fields" , ( ) => {
448- const googleApiKey = `AIza${ "a" . repeat ( 32 ) } ` ;
466+ it ( "preserves credential-shaped bytes in recognized provider replay fields" , ( ) => {
449467 const githubToken = `ghp_${ "b" . repeat ( 36 ) } ` ;
450- const awsAccessKey = "AKIAIOSFODNN7EXAMPLE" ;
451468 const encryptedDetail = JSON . stringify ( {
452469 type : "reasoning.encrypted" ,
453470 data : githubToken ,
454471 id : "reasoning-encrypted-1" ,
472+ secret : "sk-abcdef1234567890xyz" ,
455473 } ) ;
456474 const googleMsg = {
457475 role : "assistant" ,
@@ -463,22 +481,27 @@ describe("redactTranscriptMessage", () => {
463481 id : "call_1" ,
464482 name : "send_request" ,
465483 arguments : { } ,
466- thoughtSignature : awsAccessKey ,
484+ thoughtSignature : GOOGLE_CREDENTIAL_COLLISION ,
467485 } ,
468486 {
469- type : "toolCall" ,
470- id : "call_2" ,
471- name : "send_request" ,
472- arguments : { } ,
473- thoughtSignature : googleApiKey ,
487+ type : "thinking" ,
488+ thinking : "visible" ,
489+ thinkingSignature : ALIBABA_CREDENTIAL_COLLISION ,
474490 } ,
475491 ] ,
476492 } as unknown as AgentMessage ;
477493 const anthropicMsg = {
478494 role : "assistant" ,
479- api : "anthropic-messages" ,
480- provider : "anthropic" ,
481- content : [ { type : "redacted_thinking" , data : githubToken } ] ,
495+ api : "bedrock-converse-stream" ,
496+ provider : "amazon-bedrock" ,
497+ content : [
498+ {
499+ type : "thinking" ,
500+ thinking : "visible" ,
501+ signature : OPENAI_COMPAT_OPAQUE_COLLISION ,
502+ } ,
503+ { type : "redacted_thinking" , data : githubToken } ,
504+ ] ,
482505 } as unknown as AgentMessage ;
483506 const openAICompletionsMsg = {
484507 role : "assistant" ,
@@ -492,8 +515,93 @@ describe("redactTranscriptMessage", () => {
492515 arguments : { } ,
493516 thoughtSignature : encryptedDetail ,
494517 } ,
518+ {
519+ type : "toolCall" ,
520+ id : "call_secret" ,
521+ name : "send_request" ,
522+ arguments : { } ,
523+ thoughtSignature : githubToken ,
524+ } ,
495525 ] ,
496526 } as unknown as AgentMessage ;
527+ const googleOpenAICompletionsMsg = {
528+ role : "assistant" ,
529+ api : "openclaw-openai-completions-transport" ,
530+ model : "gemini-3.1-pro" ,
531+ provider : "google-compatible-proxy" ,
532+ content : [
533+ {
534+ type : "toolCall" ,
535+ id : "call_2" ,
536+ name : "send_request" ,
537+ arguments : { } ,
538+ thoughtSignature : OPENAI_COMPAT_OPAQUE_COLLISION ,
539+ } ,
540+ ] ,
541+ } as unknown as AgentMessage ;
542+ const openAIResponsesMsg = {
543+ role : "assistant" ,
544+ api : "openai-responses" ,
545+ model : "gpt-5.5" ,
546+ provider : "openai" ,
547+ content : [
548+ {
549+ type : "thinking" ,
550+ thinking : "visible" ,
551+ thinkingSignature : JSON . stringify ( {
552+ id : "reasoning-1" ,
553+ type : "reasoning" ,
554+ encrypted_content : GOOGLE_CREDENTIAL_COLLISION ,
555+ summary : [ { type : "summary_text" , text : "secret sk-abcdef1234567890xyz" } ] ,
556+ secret : "sk-abcdef1234567890xyz" ,
557+ } ) ,
558+ } ,
559+ ] ,
560+ } as unknown as AgentMessage ;
561+
562+ const googleBlocks = msgContent ( redactTranscriptMessage ( googleMsg , cfg ( "tools" ) ) ) as Array <
563+ Record < string , string >
564+ > ;
565+ expect ( googleBlocks [ 0 ] . thoughtSignature ) . toBe ( GOOGLE_CREDENTIAL_COLLISION ) ;
566+ expect ( googleBlocks [ 1 ] . thinkingSignature ) . toBe ( ALIBABA_CREDENTIAL_COLLISION ) ;
567+
568+ const anthropicBlocks = msgContent (
569+ redactTranscriptMessage ( anthropicMsg , cfg ( "tools" ) ) ,
570+ ) as Array < Record < string , string > > ;
571+ expect ( anthropicBlocks [ 0 ] . signature ) . toBe ( OPENAI_COMPAT_OPAQUE_COLLISION ) ;
572+ expect ( anthropicBlocks [ 1 ] . data ) . toBe ( githubToken ) ;
573+
574+ const completionsBlocks = msgContent (
575+ redactTranscriptMessage ( openAICompletionsMsg , cfg ( "tools" ) ) ,
576+ ) as Array < { thoughtSignature : string } > ;
577+ expect ( JSON . parse ( completionsBlocks [ 0 ] . thoughtSignature ) ) . toEqual ( {
578+ type : "reasoning.encrypted" ,
579+ data : githubToken ,
580+ id : "reasoning-encrypted-1" ,
581+ } ) ;
582+ expect ( completionsBlocks [ 1 ] . thoughtSignature ) . not . toBe ( githubToken ) ;
583+
584+ const googleCompletionsBlock = (
585+ msgContent ( redactTranscriptMessage ( googleOpenAICompletionsMsg , googleCompatCfg ( ) ) ) as Array < {
586+ thoughtSignature : string ;
587+ } >
588+ ) [ 0 ] ;
589+ expect ( googleCompletionsBlock . thoughtSignature ) . toBe ( OPENAI_COMPAT_OPAQUE_COLLISION ) ;
590+
591+ const responsesBlock = (
592+ msgContent ( redactTranscriptMessage ( openAIResponsesMsg , cfg ( "tools" ) ) ) as Array < {
593+ thinkingSignature : string ;
594+ } >
595+ ) [ 0 ] ;
596+ expect ( JSON . parse ( responsesBlock . thinkingSignature ) ) . toEqual ( {
597+ id : "reasoning-1" ,
598+ type : "reasoning" ,
599+ summary : [ ] ,
600+ encrypted_content : GOOGLE_CREDENTIAL_COLLISION ,
601+ } ) ;
602+ } ) ;
603+
604+ it ( "keeps unknown and malformed replay fields credential-safe" , ( ) => {
497605 const customProviderMsg = {
498606 role : "assistant" ,
499607 api : "custom-provider-api" ,
@@ -503,26 +611,81 @@ describe("redactTranscriptMessage", () => {
503611 {
504612 type : "thinking" ,
505613 thinking : "visible" ,
506- thinkingSignature : awsAccessKey ,
614+ thinkingSignature : ALIBABA_CREDENTIAL_COLLISION ,
615+ } ,
616+ {
617+ type : "toolCall" ,
618+ id : "call_1" ,
619+ name : "send_request" ,
620+ arguments : { } ,
621+ thoughtSignature : JSON . stringify ( {
622+ type : "reasoning.encrypted" ,
623+ data : GOOGLE_CREDENTIAL_COLLISION ,
624+ id : "reasoning-encrypted-1" ,
625+ } ) ,
626+ } ,
627+ ] ,
628+ } as unknown as AgentMessage ;
629+ const malformedGoogleMsg = {
630+ role : "assistant" ,
631+ api : "google-generative-ai" ,
632+ model : "gemini-3.1-pro" ,
633+ provider : "google" ,
634+ content : [
635+ {
636+ type : "toolCall" ,
637+ id : "call_1" ,
638+ name : "send_request" ,
639+ arguments : { } ,
640+ thoughtSignature : OPAQUE_CREDENTIAL_COLLISION ,
507641 } ,
508642 ] ,
509643 } as unknown as AgentMessage ;
644+ const malformedKnownOpaqueMessages = [
645+ {
646+ role : "assistant" ,
647+ api : "anthropic-messages" ,
648+ model : "claude-opus-4-8" ,
649+ provider : "anthropic" ,
650+ content : [
651+ {
652+ type : "thinking" ,
653+ thinking : "visible" ,
654+ thinkingSignature : "secret sk-abcdef1234567890xyz" ,
655+ } ,
656+ ] ,
657+ } ,
658+ {
659+ role : "assistant" ,
660+ api : "openai-completions" ,
661+ model : "gemini-3.1-pro" ,
662+ provider : "google" ,
663+ content : [
664+ {
665+ type : "toolCall" ,
666+ id : "call_1" ,
667+ name : "send_request" ,
668+ arguments : { } ,
669+ thoughtSignature : "secret sk-abcdef1234567890xyz" ,
670+ } ,
671+ ] ,
672+ } ,
673+ ] as unknown as AgentMessage [ ] ;
510674
511675 expect (
512- JSON . stringify ( msgContent ( redactTranscriptMessage ( googleMsg , cfg ( "tools" ) ) ) ) ,
513- ) . not . toContain ( awsAccessKey ) ;
514- expect (
515- JSON . stringify ( msgContent ( redactTranscriptMessage ( googleMsg , cfg ( "tools" ) ) ) ) ,
516- ) . not . toContain ( googleApiKey ) ;
517- expect (
518- JSON . stringify ( msgContent ( redactTranscriptMessage ( anthropicMsg , cfg ( "tools" ) ) ) ) ,
519- ) . not . toContain ( githubToken ) ;
520- expect (
521- JSON . stringify ( msgContent ( redactTranscriptMessage ( openAICompletionsMsg , cfg ( "tools" ) ) ) ) ,
522- ) . not . toContain ( githubToken ) ;
676+ JSON . stringify ( msgContent ( redactTranscriptMessage ( customProviderMsg , cfg ( "tools" ) ) ) ) ,
677+ ) . not . toContain ( ALIBABA_CREDENTIAL_COLLISION ) ;
523678 expect (
524679 JSON . stringify ( msgContent ( redactTranscriptMessage ( customProviderMsg , cfg ( "tools" ) ) ) ) ,
525- ) . not . toContain ( awsAccessKey ) ;
680+ ) . not . toContain ( GOOGLE_CREDENTIAL_COLLISION ) ;
681+ expect (
682+ JSON . stringify ( msgContent ( redactTranscriptMessage ( malformedGoogleMsg , cfg ( "tools" ) ) ) ) ,
683+ ) . not . toContain ( OPAQUE_CREDENTIAL_COLLISION ) ;
684+ for ( const message of malformedKnownOpaqueMessages ) {
685+ expect (
686+ JSON . stringify ( msgContent ( redactTranscriptMessage ( message , cfg ( "tools" ) ) ) ) ,
687+ ) . not . toContain ( "sk-abcdef1234567890xyz" ) ;
688+ }
526689 } ) ;
527690
528691 it ( "redacts provider-shaped fields when the assistant route is missing" , ( ) => {
0 commit comments