@@ -400,25 +400,26 @@ describe("managed startup agent environment", () => {
400400 ) . toThrow ( message ) ;
401401 } ) ;
402402
403- it . each (
404- MANAGED_STARTUP_AGENTS ,
405- ) ( "derives every unsupported $0 runtime unset from the closed contract" , ( agent ) => {
406- const result = mapManagedStartupProfileToAgentEnvironment ( PROFILES [ agent ] ( ) , {
407- NEMOCLAW_AUTO_PAIR_DEADLINE_SECS : "30" ,
408- NEMOCLAW_AUTO_PAIR_FAST_DEADLINE_SECS : "3" ,
409- NEMOCLAW_AUTO_PAIR_FAST_REENTRY_INTERVAL_SECS : "0.25" ,
410- NEMOCLAW_AUTO_PAIR_FAST_REENTRY_POLLS : "3" ,
411- NEMOCLAW_AUTO_PAIR_RUN_TIMEOUT_SECS : "10" ,
412- NEMOCLAW_AUTO_PAIR_SLOW_INTERVAL_SECS : "600" ,
413- } ) ;
414- const unsets = new Set ( result . applicationRuntime . unsetEnvironment ) ;
415- for ( const obligation of MANAGED_STARTUP_RUNTIME_CLEANUP_OBLIGATIONS ) {
416- expect ( unsets . has ( obligation . input ) ) . toBe ( ! obligation . supportedFor . includes ( agent ) ) ;
417- }
418- for ( const name of OPENCLAW_APPLICATION_RUNTIME_NAMES ) {
419- expect ( unsets . has ( name ) ) . toBe ( agent !== "openclaw" ) ;
420- }
421- } ) ;
403+ it . each ( MANAGED_STARTUP_AGENTS ) (
404+ "derives every unsupported $0 runtime unset from the closed contract" ,
405+ ( agent ) => {
406+ const result = mapManagedStartupProfileToAgentEnvironment ( PROFILES [ agent ] ( ) , {
407+ NEMOCLAW_AUTO_PAIR_DEADLINE_SECS : "30" ,
408+ NEMOCLAW_AUTO_PAIR_FAST_DEADLINE_SECS : "3" ,
409+ NEMOCLAW_AUTO_PAIR_FAST_REENTRY_INTERVAL_SECS : "0.25" ,
410+ NEMOCLAW_AUTO_PAIR_FAST_REENTRY_POLLS : "3" ,
411+ NEMOCLAW_AUTO_PAIR_RUN_TIMEOUT_SECS : "10" ,
412+ NEMOCLAW_AUTO_PAIR_SLOW_INTERVAL_SECS : "600" ,
413+ } ) ;
414+ const unsets = new Set ( result . applicationRuntime . unsetEnvironment ) ;
415+ for ( const obligation of MANAGED_STARTUP_RUNTIME_CLEANUP_OBLIGATIONS ) {
416+ expect ( unsets . has ( obligation . input ) ) . toBe ( ! obligation . supportedFor . includes ( agent ) ) ;
417+ }
418+ for ( const name of OPENCLAW_APPLICATION_RUNTIME_NAMES ) {
419+ expect ( unsets . has ( name ) ) . toBe ( agent !== "openclaw" ) ;
420+ }
421+ } ,
422+ ) ;
422423
423424 it ( "keeps the profile mapper independent from mutable process-global runtime input" , ( ) => {
424425 const name = "NEMOCLAW_AUTO_PAIR_FAST_REENTRY_POLLS" ;
@@ -514,7 +515,7 @@ describe("managed startup agent environment", () => {
514515 } ) ;
515516 } ) ;
516517
517- it ( "keeps DCode routing and auto-approval in root-owned files instead of ambient runtime env " , ( ) => {
518+ it ( "keeps DCode routing, provider identity, and auto-approval in root-owned files" , ( ) => {
518519 const result = mapManagedStartupProfileToAgentEnvironment ( dcodeProfile ( ) , {
519520 NEMOCLAW_AUTO_PAIR_FAST_REENTRY_INTERVAL_SECS : "not-a-number" ,
520521 } ) ;
@@ -538,6 +539,7 @@ describe("managed startup agent environment", () => {
538539 const expectedDcodeRuntime = { ...result . configurationEnvironment } ;
539540 delete expectedDcodeRuntime . NEMOCLAW_INFERENCE_BASE_URL ;
540541 delete expectedDcodeRuntime . NEMOCLAW_REASONING_EFFORT ;
542+ delete expectedDcodeRuntime . NEMOCLAW_UPSTREAM_PROVIDER ;
541543 for ( const name of [
542544 "HTTP_PROXY" ,
543545 "HTTPS_PROXY" ,
@@ -566,6 +568,7 @@ describe("managed startup agent environment", () => {
566568 expect ( result . runtimeEnvironment ) . not . toHaveProperty ( "HTTPS_PROXY" ) ;
567569 expect ( result . runtimeEnvironment ) . not . toHaveProperty ( "NEMOCLAW_INFERENCE_BASE_URL" ) ;
568570 expect ( result . runtimeEnvironment ) . not . toHaveProperty ( "NEMOCLAW_REASONING_EFFORT" ) ;
571+ expect ( result . runtimeEnvironment ) . not . toHaveProperty ( "NEMOCLAW_UPSTREAM_PROVIDER" ) ;
569572
570573 expect ( result . materials ) . toEqual ( [
571574 {
@@ -591,6 +594,15 @@ describe("managed startup agent environment", () => {
591594 group : "root" ,
592595 mode : 0o444 ,
593596 } ,
597+ {
598+ kind : "root-owned-file" ,
599+ legacyInput : "NEMOCLAW_UPSTREAM_PROVIDER" ,
600+ path : "/usr/local/share/nemoclaw/dcode-upstream-provider" ,
601+ contents : "openrouter\n" ,
602+ owner : "root" ,
603+ group : "root" ,
604+ mode : 0o444 ,
605+ } ,
594606 {
595607 kind : "root-owned-file" ,
596608 legacyInput : "NEMOCLAW_PROXY_HOST" ,
@@ -678,29 +690,43 @@ describe("managed startup agent environment", () => {
678690 } ) ;
679691 } ) ;
680692
681- it . each (
682- MANAGED_STARTUP_AGENTS ,
683- ) ( "represents the complete $0 Docker/start affordance inventory" , ( agent ) => {
684- const result = mapManagedStartupProfileToAgentEnvironment ( PROFILES [ agent ] ( ) ) ;
685- expect ( representedLegacyInputs ( result ) ) . toEqual (
686- MANAGED_STARTUP_PROFILE_AFFORDANCE_INVENTORY [ agent ]
687- . map ( ( affordance ) => affordance . input )
688- . sort ( ) ,
689- ) ;
690- const messagingActions = result . actions . filter (
691- ( action ) => action . kind === "apply-messaging-plan" ,
692- ) ;
693- expect ( messagingActions . map ( ( { phase, runAs } ) => [ phase , runAs ] ) ) . toEqual (
694- agent === "langchain-deepagents-code"
695- ? [ ]
696- : [
697- [ "runtime-setup" , "root" ] ,
698- [ "post-agent-install" , "sandbox" ] ,
699- ] ,
700- ) ;
701- expect ( messagingActions . map ( ( action ) => String ( action . phase ) ) ) . not . toContain ( "agent-install" ) ;
693+ it ( "materializes the longest DCode upstream provider accepted by its runtime (#7112)" , ( ) => {
694+ const profile = dcodeProfile ( ) ;
695+ const upstreamProvider = "a" . repeat ( 64 ) ;
696+ const result = mapManagedStartupProfileToAgentEnvironment ( {
697+ ...profile ,
698+ inference : { ...profile . inference , upstreamProvider } ,
699+ } ) ;
700+
701+ expect (
702+ result . materials . find ( ( material ) => material . legacyInput === "NEMOCLAW_UPSTREAM_PROVIDER" ) ,
703+ ) . toMatchObject ( { contents : `${ upstreamProvider } \n` } ) ;
702704 } ) ;
703705
706+ it . each ( MANAGED_STARTUP_AGENTS ) (
707+ "represents the complete $0 Docker/start affordance inventory" ,
708+ ( agent ) => {
709+ const result = mapManagedStartupProfileToAgentEnvironment ( PROFILES [ agent ] ( ) ) ;
710+ expect ( representedLegacyInputs ( result ) ) . toEqual (
711+ MANAGED_STARTUP_PROFILE_AFFORDANCE_INVENTORY [ agent ]
712+ . map ( ( affordance ) => affordance . input )
713+ . sort ( ) ,
714+ ) ;
715+ const messagingActions = result . actions . filter (
716+ ( action ) => action . kind === "apply-messaging-plan" ,
717+ ) ;
718+ expect ( messagingActions . map ( ( { phase, runAs } ) => [ phase , runAs ] ) ) . toEqual (
719+ agent === "langchain-deepagents-code"
720+ ? [ ]
721+ : [
722+ [ "runtime-setup" , "root" ] ,
723+ [ "post-agent-install" , "sandbox" ] ,
724+ ] ,
725+ ) ;
726+ expect ( messagingActions . map ( ( action ) => String ( action . phase ) ) ) . not . toContain ( "agent-install" ) ;
727+ } ,
728+ ) ;
729+
704730 it ( "uses explicit clear states without erasing launch-only ambient proxy credentials" , ( ) => {
705731 const openclawBase = openClawProfile ( ) ;
706732 assert ( openclawBase . agentConfig . agent === "openclaw" , "fixture mismatch" ) ;
@@ -871,6 +897,21 @@ describe("managed startup agent environment", () => {
871897 ) ;
872898 } ) ;
873899
900+ it . each ( [ "provider-π" , `p${ "x" . repeat ( 64 ) } ` , "-ollama-local" ] ) (
901+ "rejects unsupported DCode provider identifier %s before materialization (#7112)" ,
902+ ( upstreamProvider ) => {
903+ const base = dcodeProfile ( ) ;
904+ const profile : ManagedStartupProfile = {
905+ ...base ,
906+ inference : { ...base . inference , upstreamProvider } ,
907+ } ;
908+
909+ expect ( ( ) => mapManagedStartupProfileToAgentEnvironment ( profile ) ) . toThrow (
910+ / m u s t s t a r t w i t h a n A S C I I l e t t e r o r d i g i t a n d c o n t a i n 1 - 6 4 A S C I I l e t t e r s , d i g i t s , d o t s , u n d e r s c o r e s , o r h y p h e n s f o r D C o d e / u,
911+ ) ;
912+ } ,
913+ ) ;
914+
874915 it ( "revalidates typed input while keeping DCode host proxy intent outside its pinned runtime" , ( ) => {
875916 const dcodeBase = dcodeProfile ( ) ;
876917 const profile : ManagedStartupProfile = {
0 commit comments